ActionBarView.java revision 9146ac706265cd8cce66907e617bc8572152eb97
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.widget; 18 19import com.android.internal.R; 20import com.android.internal.view.menu.ActionMenuItem; 21import com.android.internal.view.menu.ActionMenuView; 22import com.android.internal.view.menu.MenuBuilder; 23 24import android.app.ActionBar; 25import android.app.ActionBar.NavigationCallback; 26import android.app.Activity; 27import android.content.Context; 28import android.content.pm.ApplicationInfo; 29import android.content.pm.PackageManager; 30import android.content.res.TypedArray; 31import android.graphics.PorterDuff; 32import android.graphics.PorterDuffColorFilter; 33import android.graphics.drawable.Drawable; 34import android.text.TextUtils.TruncateAt; 35import android.util.AttributeSet; 36import android.util.DisplayMetrics; 37import android.view.ActionMode; 38import android.view.Gravity; 39import android.view.LayoutInflater; 40import android.view.Menu; 41import android.view.View; 42import android.view.ViewGroup; 43import android.widget.AdapterView; 44import android.widget.ImageView; 45import android.widget.LinearLayout; 46import android.widget.Spinner; 47import android.widget.SpinnerAdapter; 48import android.widget.TextView; 49 50/** 51 * @hide 52 */ 53public class ActionBarView extends ViewGroup { 54 private static final String TAG = "ActionBarView"; 55 56 // TODO: This must be defined in the default theme 57 private static final int CONTENT_PADDING_DIP = 3; 58 private static final int CONTENT_SPACING_DIP = 6; 59 private static final int CONTENT_ACTION_SPACING_DIP = 12; 60 61 /** 62 * Display options applied by default 63 */ 64 public static final int DISPLAY_DEFAULT = 0; 65 66 /** 67 * Display options that require re-layout as opposed to a simple invalidate 68 */ 69 private static final int DISPLAY_RELAYOUT_MASK = 70 ActionBar.DISPLAY_HIDE_HOME | 71 ActionBar.DISPLAY_USE_LOGO; 72 73 private final int mContentHeight; 74 75 private int mNavigationMode; 76 private int mDisplayOptions; 77 private int mSpacing; 78 private int mActionSpacing; 79 private CharSequence mTitle; 80 private CharSequence mSubtitle; 81 private Drawable mIcon; 82 private Drawable mLogo; 83 84 private ImageView mIconView; 85 private ImageView mLogoView; 86 private LinearLayout mTitleLayout; 87 private TextView mTitleView; 88 private TextView mSubtitleView; 89 private Spinner mSpinner; 90 private LinearLayout mTabLayout; 91 private View mCustomNavView; 92 93 private int mTitleStyleRes; 94 private int mSubtitleStyleRes; 95 96 private boolean mShowMenu; 97 private boolean mUserTitle; 98 99 private MenuBuilder mOptionsMenu; 100 private ActionMenuView mMenuView; 101 102 private ActionBarContextView mContextView; 103 104 private ActionMenuItem mLogoNavItem; 105 106 private NavigationCallback mCallback; 107 108 private final AdapterView.OnItemSelectedListener mNavItemSelectedListener = 109 new AdapterView.OnItemSelectedListener() { 110 public void onItemSelected(AdapterView parent, View view, int position, long id) { 111 if (mCallback != null) { 112 mCallback.onNavigationItemSelected(position, id); 113 } 114 } 115 public void onNothingSelected(AdapterView parent) { 116 // Do nothing 117 } 118 }; 119 120 private OnClickListener mHomeClickListener = null; 121 122 public ActionBarView(Context context, AttributeSet attrs) { 123 super(context, attrs); 124 125 final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 126 127 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar); 128 129 final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0); 130 131 if (colorFilter != 0) { 132 final Drawable d = getBackground(); 133 d.setDither(true); 134 d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY)); 135 } 136 137 ApplicationInfo info = context.getApplicationInfo(); 138 PackageManager pm = context.getPackageManager(); 139 mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, 140 ActionBar.NAVIGATION_MODE_STANDARD); 141 mTitle = a.getText(R.styleable.ActionBar_title); 142 mSubtitle = a.getText(R.styleable.ActionBar_subtitle); 143 mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT); 144 145 mLogo = a.getDrawable(R.styleable.ActionBar_logo); 146 if (mLogo == null) { 147 mLogo = info.loadLogo(pm); 148 } 149 mIcon = a.getDrawable(R.styleable.ActionBar_icon); 150 if (mIcon == null) { 151 mIcon = info.loadIcon(pm); 152 } 153 154 Drawable background = a.getDrawable(R.styleable.ActionBar_background); 155 if (background != null) { 156 setBackgroundDrawable(background); 157 } 158 159 mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0); 160 mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0); 161 162 final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0); 163 if (customNavId != 0) { 164 LayoutInflater inflater = LayoutInflater.from(context); 165 mCustomNavView = (View) inflater.inflate(customNavId, null); 166 mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM; 167 } 168 169 mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0); 170 171 a.recycle(); 172 173 // TODO: Set this in the theme 174 mSpacing = (int) (CONTENT_SPACING_DIP * metrics.density + 0.5f); 175 mActionSpacing = (int) (CONTENT_ACTION_SPACING_DIP * metrics.density + 0.5f); 176 177 if (mLogo != null || mIcon != null || mTitle != null) { 178 mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle); 179 mHomeClickListener = new OnClickListener() { 180 public void onClick(View v) { 181 Context context = getContext(); 182 if (context instanceof Activity) { 183 Activity activity = (Activity) context; 184 activity.onOptionsItemSelected(mLogoNavItem); 185 } 186 } 187 }; 188 } 189 } 190 191 @Override 192 public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) { 193 // No starting an action mode for an action bar child! (Where would it go?) 194 return null; 195 } 196 197 public void setCallback(NavigationCallback callback) { 198 mCallback = callback; 199 } 200 201 public void setMenu(Menu menu) { 202 MenuBuilder builder = (MenuBuilder) menu; 203 mOptionsMenu = builder; 204 if (mMenuView != null) { 205 removeView(mMenuView); 206 } 207 final ActionMenuView menuView = (ActionMenuView) builder.getMenuView( 208 MenuBuilder.TYPE_ACTION_BUTTON, null); 209 mActionSpacing = menuView.getItemMargin(); 210 final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, 211 LayoutParams.MATCH_PARENT); 212 menuView.setLayoutParams(layoutParams); 213 addView(menuView); 214 mMenuView = menuView; 215 } 216 217 public boolean showOverflowMenu() { 218 if (mMenuView != null) { 219 return mMenuView.showOverflowMenu(); 220 } 221 return false; 222 } 223 224 public boolean hideOverflowMenu() { 225 if (mMenuView != null) { 226 return mMenuView.hideOverflowMenu(); 227 } 228 return false; 229 } 230 231 public boolean isOverflowMenuShowing() { 232 if (mMenuView != null) { 233 return mMenuView.isOverflowMenuShowing(); 234 } 235 return false; 236 } 237 238 public boolean isOverflowReserved() { 239 return mMenuView != null && mMenuView.isOverflowReserved(); 240 } 241 242 public void setCustomNavigationView(View view) { 243 mCustomNavView = view; 244 if (view != null) { 245 setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM); 246 } 247 } 248 249 public CharSequence getTitle() { 250 return mTitle; 251 } 252 253 /** 254 * Set the action bar title. This will always replace or override window titles. 255 * @param title Title to set 256 * 257 * @see #setWindowTitle(CharSequence) 258 */ 259 public void setTitle(CharSequence title) { 260 mUserTitle = true; 261 setTitleImpl(title); 262 } 263 264 /** 265 * Set the window title. A window title will always be replaced or overridden by a user title. 266 * @param title Title to set 267 * 268 * @see #setTitle(CharSequence) 269 */ 270 public void setWindowTitle(CharSequence title) { 271 if (!mUserTitle) { 272 setTitleImpl(title); 273 } 274 } 275 276 private void setTitleImpl(CharSequence title) { 277 mTitle = title; 278 if (mTitleView != null) { 279 mTitleView.setText(title); 280 } 281 if (mLogoNavItem != null) { 282 mLogoNavItem.setTitle(title); 283 } 284 } 285 286 public CharSequence getSubtitle() { 287 return mSubtitle; 288 } 289 290 public void setSubtitle(CharSequence subtitle) { 291 mSubtitle = subtitle; 292 if (mSubtitleView != null) { 293 mSubtitleView.setText(subtitle); 294 } 295 } 296 297 public void setDisplayOptions(int options) { 298 final int flagsChanged = options ^ mDisplayOptions; 299 mDisplayOptions = options; 300 if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) { 301 final int vis = (options & ActionBar.DISPLAY_HIDE_HOME) != 0 ? GONE : VISIBLE; 302 if (mLogoView != null) { 303 mLogoView.setVisibility(vis); 304 } 305 if (mIconView != null) { 306 mIconView.setVisibility(vis); 307 } 308 309 requestLayout(); 310 } else { 311 invalidate(); 312 } 313 } 314 315 public void setNavigationMode(int mode) { 316 final int oldMode = mNavigationMode; 317 if (mode != oldMode) { 318 switch (oldMode) { 319 case ActionBar.NAVIGATION_MODE_STANDARD: 320 if (mTitleLayout != null) { 321 removeView(mTitleLayout); 322 mTitleLayout = null; 323 mTitleView = null; 324 mSubtitleView = null; 325 } 326 break; 327 case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST: 328 if (mSpinner != null) { 329 removeView(mSpinner); 330 mSpinner = null; 331 } 332 break; 333 case ActionBar.NAVIGATION_MODE_CUSTOM: 334 if (mCustomNavView != null) { 335 removeView(mCustomNavView); 336 mCustomNavView = null; 337 } 338 break; 339 case ActionBar.NAVIGATION_MODE_TABS: 340 if (mTabLayout != null) { 341 removeView(mTabLayout); 342 mTabLayout = null; 343 } 344 } 345 346 switch (mode) { 347 case ActionBar.NAVIGATION_MODE_STANDARD: 348 initTitle(); 349 break; 350 case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST: 351 mSpinner = new Spinner(mContext, null, 352 com.android.internal.R.attr.dropDownSpinnerStyle); 353 mSpinner.setOnItemSelectedListener(mNavItemSelectedListener); 354 addView(mSpinner); 355 break; 356 case ActionBar.NAVIGATION_MODE_CUSTOM: 357 addView(mCustomNavView); 358 break; 359 case ActionBar.NAVIGATION_MODE_TABS: 360 mTabLayout = new LinearLayout(getContext()); 361 addView(mTabLayout); 362 break; 363 } 364 mNavigationMode = mode; 365 requestLayout(); 366 } 367 } 368 369 public void setDropdownAdapter(SpinnerAdapter adapter) { 370 mSpinner.setAdapter(adapter); 371 } 372 373 public void setDropdownSelectedPosition(int position) { 374 mSpinner.setSelection(position); 375 } 376 377 public int getDropdownSelectedPosition() { 378 return mSpinner.getSelectedItemPosition(); 379 } 380 381 public View getCustomNavigationView() { 382 return mCustomNavView; 383 } 384 385 public int getNavigationMode() { 386 return mNavigationMode; 387 } 388 389 public int getDisplayOptions() { 390 return mDisplayOptions; 391 } 392 393 private TabView createTabView(ActionBar.Tab tab) { 394 final TabView tabView = new TabView(getContext(), tab); 395 tabView.setFocusable(true); 396 tabView.setOnClickListener(new TabClickListener()); 397 return tabView; 398 } 399 400 public void addTab(ActionBar.Tab tab) { 401 final boolean isFirst = mTabLayout.getChildCount() == 0; 402 final TabView tabView = createTabView(tab); 403 mTabLayout.addView(tabView); 404 if (isFirst) { 405 tabView.setSelected(true); 406 } 407 } 408 409 public void insertTab(ActionBar.Tab tab, int position) { 410 final boolean isFirst = mTabLayout.getChildCount() == 0; 411 final TabView tabView = createTabView(tab); 412 mTabLayout.addView(tabView, position); 413 if (isFirst) { 414 tabView.setSelected(true); 415 } 416 } 417 418 public void removeTabAt(int position) { 419 mTabLayout.removeViewAt(position); 420 } 421 422 @Override 423 protected LayoutParams generateDefaultLayoutParams() { 424 // Used by custom nav views if they don't supply layout params. Everything else 425 // added to an ActionBarView should have them already. 426 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 427 } 428 429 @Override 430 protected void onFinishInflate() { 431 super.onFinishInflate(); 432 433 if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) { 434 if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) { 435 mLogoView = new ImageView(getContext()); 436 mLogoView.setAdjustViewBounds(true); 437 mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 438 LayoutParams.MATCH_PARENT)); 439 mLogoView.setImageDrawable(mLogo); 440 mLogoView.setClickable(true); 441 mLogoView.setFocusable(true); 442 mLogoView.setOnClickListener(mHomeClickListener); 443 addView(mLogoView); 444 } else if (mIcon != null) { 445 mIconView = new ImageView(getContext()); 446 mIconView.setAdjustViewBounds(true); 447 mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 448 LayoutParams.MATCH_PARENT)); 449 mIconView.setImageDrawable(mIcon); 450 mIconView.setClickable(true); 451 mIconView.setFocusable(true); 452 mIconView.setOnClickListener(mHomeClickListener); 453 addView(mIconView); 454 } 455 } 456 457 switch (mNavigationMode) { 458 case ActionBar.NAVIGATION_MODE_STANDARD: 459 if (mLogoView == null) { 460 initTitle(); 461 } 462 break; 463 464 case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST: 465 throw new UnsupportedOperationException( 466 "Inflating dropdown list navigation isn't supported yet!"); 467 468 case ActionBar.NAVIGATION_MODE_TABS: 469 throw new UnsupportedOperationException( 470 "Inflating tab navigation isn't supported yet!"); 471 472 case ActionBar.NAVIGATION_MODE_CUSTOM: 473 if (mCustomNavView != null) { 474 addView(mCustomNavView); 475 } 476 break; 477 } 478 } 479 480 private void initTitle() { 481 LayoutInflater inflater = LayoutInflater.from(getContext()); 482 mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null); 483 mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title); 484 mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle); 485 486 if (mTitleStyleRes != 0) { 487 mTitleView.setTextAppearance(mContext, mTitleStyleRes); 488 } 489 if (mTitle != null) { 490 mTitleView.setText(mTitle); 491 } 492 493 if (mSubtitleStyleRes != 0) { 494 mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes); 495 } 496 if (mSubtitle != null) { 497 mSubtitleView.setText(mSubtitle); 498 mSubtitleView.setVisibility(VISIBLE); 499 } 500 501 addView(mTitleLayout); 502 } 503 504 public void setTabSelected(int position) { 505 final int tabCount = mTabLayout.getChildCount(); 506 for (int i = 0; i < tabCount; i++) { 507 final View child = mTabLayout.getChildAt(i); 508 child.setSelected(i == position); 509 } 510 } 511 512 public void setContextView(ActionBarContextView view) { 513 mContextView = view; 514 } 515 516 @Override 517 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 518 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 519 if (widthMode != MeasureSpec.EXACTLY) { 520 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 521 "with android:layout_width=\"match_parent\" (or fill_parent)"); 522 } 523 524 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 525 if (heightMode != MeasureSpec.AT_MOST) { 526 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 527 "with android:layout_height=\"wrap_content\""); 528 } 529 530 int contentWidth = MeasureSpec.getSize(widthMeasureSpec); 531 532 int maxHeight = mContentHeight > 0 ? 533 mContentHeight : MeasureSpec.getSize(heightMeasureSpec); 534 535 final int verticalPadding = getPaddingTop() + getPaddingBottom(); 536 int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); 537 final int height = maxHeight - verticalPadding; 538 final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); 539 540 if (mLogoView != null && mLogoView.getVisibility() != GONE) { 541 availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, mSpacing); 542 } 543 if (mIconView != null && mIconView.getVisibility() != GONE) { 544 availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, mSpacing); 545 } 546 547 if (mMenuView != null) { 548 availableWidth = measureChildView(mMenuView, availableWidth, 549 childSpecHeight, 0); 550 } 551 552 switch (mNavigationMode) { 553 case ActionBar.NAVIGATION_MODE_STANDARD: 554 if (mTitleLayout != null) { 555 measureChildView(mTitleLayout, availableWidth, childSpecHeight, mSpacing); 556 } 557 break; 558 case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST: 559 if (mSpinner != null) { 560 mSpinner.measure( 561 MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 562 MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); 563 } 564 break; 565 case ActionBar.NAVIGATION_MODE_CUSTOM: 566 if (mCustomNavView != null) { 567 LayoutParams lp = mCustomNavView.getLayoutParams(); 568 final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? 569 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 570 final int customNavWidth = lp.width >= 0 ? 571 Math.min(lp.width, availableWidth) : availableWidth; 572 573 // If the action bar is wrapping to its content height, don't allow a custom 574 // view to MATCH_PARENT. 575 int customNavHeightMode; 576 if (mContentHeight <= 0) { 577 customNavHeightMode = MeasureSpec.AT_MOST; 578 } else { 579 customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? 580 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 581 } 582 final int customNavHeight = lp.height >= 0 ? 583 Math.min(lp.height, height) : height; 584 mCustomNavView.measure( 585 MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode), 586 MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode)); 587 } 588 break; 589 case ActionBar.NAVIGATION_MODE_TABS: 590 if (mTabLayout != null) { 591 mTabLayout.measure( 592 MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 593 MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); 594 } 595 break; 596 } 597 598 if (mContentHeight <= 0) { 599 int measuredHeight = 0; 600 final int count = getChildCount(); 601 for (int i = 0; i < count; i++) { 602 View v = getChildAt(i); 603 int paddedViewHeight = v.getMeasuredHeight() + verticalPadding; 604 if (paddedViewHeight > measuredHeight) { 605 measuredHeight = paddedViewHeight; 606 } 607 } 608 setMeasuredDimension(contentWidth, measuredHeight); 609 } else { 610 setMeasuredDimension(contentWidth, maxHeight); 611 } 612 613 if (mContextView != null) { 614 mContextView.setHeight(getMeasuredHeight()); 615 } 616 } 617 618 private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) { 619 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 620 childSpecHeight); 621 622 availableWidth -= child.getMeasuredWidth(); 623 availableWidth -= spacing; 624 625 return availableWidth; 626 } 627 628 @Override 629 protected void onLayout(boolean changed, int l, int t, int r, int b) { 630 int x = getPaddingLeft(); 631 final int y = getPaddingTop(); 632 final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); 633 634 if (mLogoView != null && mLogoView.getVisibility() != GONE) { 635 x += positionChild(mLogoView, x, y, contentHeight) + mSpacing; 636 } 637 if (mIconView != null && mIconView.getVisibility() != GONE) { 638 x += positionChild(mIconView, x, y, contentHeight) + mSpacing; 639 } 640 641 switch (mNavigationMode) { 642 case ActionBar.NAVIGATION_MODE_STANDARD: 643 if (mTitleLayout != null) { 644 x += positionChild(mTitleLayout, x, y, contentHeight) + mSpacing; 645 } 646 break; 647 case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST: 648 if (mSpinner != null) { 649 x += positionChild(mSpinner, x, y, contentHeight) + mSpacing; 650 } 651 break; 652 case ActionBar.NAVIGATION_MODE_CUSTOM: 653 if (mCustomNavView != null) { 654 x += positionChild(mCustomNavView, x, y, contentHeight) + mSpacing; 655 } 656 break; 657 case ActionBar.NAVIGATION_MODE_TABS: 658 if (mTabLayout != null) { 659 x += positionChild(mTabLayout, x, y, contentHeight) + mSpacing; 660 } 661 } 662 663 x = r - l - getPaddingRight(); 664 665 if (mMenuView != null) { 666 x -= positionChildInverse(mMenuView, x + mActionSpacing, y, contentHeight) 667 - mActionSpacing; 668 } 669 } 670 671 private int positionChild(View child, int x, int y, int contentHeight) { 672 int childWidth = child.getMeasuredWidth(); 673 int childHeight = child.getMeasuredHeight(); 674 int childTop = y + (contentHeight - childHeight) / 2; 675 676 child.layout(x, childTop, x + childWidth, childTop + childHeight); 677 678 return childWidth; 679 } 680 681 private int positionChildInverse(View child, int x, int y, int contentHeight) { 682 int childWidth = child.getMeasuredWidth(); 683 int childHeight = child.getMeasuredHeight(); 684 int childTop = y + (contentHeight - childHeight) / 2; 685 686 child.layout(x - childWidth, childTop, x, childTop + childHeight); 687 688 return childWidth; 689 } 690 691 private static class TabView extends LinearLayout { 692 private ActionBar.Tab mTab; 693 694 public TabView(Context context, ActionBar.Tab tab) { 695 super(context); 696 mTab = tab; 697 698 // TODO Style tabs based on the theme 699 700 final Drawable icon = tab.getIcon(); 701 final CharSequence text = tab.getText(); 702 703 if (icon != null) { 704 ImageView iconView = new ImageView(context); 705 iconView.setImageDrawable(icon); 706 LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 707 LayoutParams.WRAP_CONTENT); 708 lp.gravity = Gravity.CENTER_VERTICAL; 709 iconView.setLayoutParams(lp); 710 addView(iconView); 711 } 712 713 if (text != null) { 714 TextView textView = new TextView(context); 715 textView.setText(text); 716 textView.setSingleLine(); 717 textView.setEllipsize(TruncateAt.END); 718 LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 719 LayoutParams.WRAP_CONTENT); 720 lp.gravity = Gravity.CENTER_VERTICAL; 721 textView.setLayoutParams(lp); 722 addView(textView); 723 } 724 725 setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 726 LayoutParams.MATCH_PARENT, 1)); 727 } 728 729 public ActionBar.Tab getTab() { 730 return mTab; 731 } 732 } 733 734 private class TabClickListener implements OnClickListener { 735 public void onClick(View view) { 736 TabView tabView = (TabView) view; 737 tabView.getTab().select(); 738 final int tabCount = mTabLayout.getChildCount(); 739 for (int i = 0; i < tabCount; i++) { 740 final View child = mTabLayout.getChildAt(i); 741 child.setSelected(child == view); 742 } 743 } 744 } 745} 746