FileDocCategorySizeDatePackage
TabWidget.javaAPI DocAndroid 5.1 API20536Thu Mar 12 22:22:10 GMT 2015android.widget

TabWidget

public class TabWidget extends LinearLayout implements android.view.View.OnFocusChangeListener
Displays a list of tab labels representing each page in the parent's tab collection. The container object for this widget is {@link android.widget.TabHost TabHost}. When the user selects a tab, this object sends a message to the parent container, TabHost, to tell it to switch the displayed page. You typically won't use many methods directly on this object. The container TabHost is used to add labels, add the callback handler, and manage callbacks. You might call this object to iterate the list of tabs, or to tweak the layout of the tab list, but most methods should be called on the containing TabHost object.
attr
ref android.R.styleable#TabWidget_divider
attr
ref android.R.styleable#TabWidget_tabStripEnabled
attr
ref android.R.styleable#TabWidget_tabStripLeft
attr
ref android.R.styleable#TabWidget_tabStripRight

Fields Summary
private OnTabSelectionChanged
mSelectionChangedListener
private int
mSelectedTab
private android.graphics.drawable.Drawable
mLeftStrip
private android.graphics.drawable.Drawable
mRightStrip
private boolean
mDrawBottomStrips
private boolean
mStripMoved
private final android.graphics.Rect
mBounds
private int
mImposedTabsHeight
private int[]
mImposedTabWidths
Constructors Summary
public TabWidget(android.content.Context context)


       
        this(context, null);
    
public TabWidget(android.content.Context context, android.util.AttributeSet attrs)

        this(context, attrs, com.android.internal.R.attr.tabWidgetStyle);
    
public TabWidget(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)

        this(context, attrs, defStyleAttr, 0);
    
public TabWidget(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)

        super(context, attrs, defStyleAttr, defStyleRes);

        final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);

        setStripEnabled(a.getBoolean(R.styleable.TabWidget_tabStripEnabled, true));
        setLeftStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripLeft));
        setRightStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripRight));

        a.recycle();

        initTabWidget();
    
Methods Summary
public voidaddView(android.view.View child)

        if (child.getLayoutParams() == null) {
            final LinearLayout.LayoutParams lp = new LayoutParams(
                    0,
                    ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
            lp.setMargins(0, 0, 0, 0);
            child.setLayoutParams(lp);
        }

        // Ensure you can navigate to the tab with the keyboard, and you can touch it
        child.setFocusable(true);
        child.setClickable(true);

        super.addView(child);

        // TODO: detect this via geometry with a tabwidget listener rather
        // than potentially interfere with the view's listener
        child.setOnClickListener(new TabClickListener(getTabCount() - 1));
        child.setOnFocusChangeListener(this);
    
public voidchildDrawableStateChanged(android.view.View child)

        if (getTabCount() > 0 && child == getChildTabViewAt(mSelectedTab)) {
            // To make sure that the bottom strip is redrawn
            invalidate();
        }
        super.childDrawableStateChanged(child);
    
public voiddispatchDraw(android.graphics.Canvas canvas)

        super.dispatchDraw(canvas);

        // Do nothing if there are no tabs.
        if (getTabCount() == 0) return;

        // If the user specified a custom view for the tab indicators, then
        // do not draw the bottom strips.
        if (!mDrawBottomStrips) {
            // Skip drawing the bottom strips.
            return;
        }

        final View selectedChild = getChildTabViewAt(mSelectedTab);

        final Drawable leftStrip = mLeftStrip;
        final Drawable rightStrip = mRightStrip;

        leftStrip.setState(selectedChild.getDrawableState());
        rightStrip.setState(selectedChild.getDrawableState());

        if (mStripMoved) {
            final Rect bounds = mBounds;
            bounds.left = selectedChild.getLeft();
            bounds.right = selectedChild.getRight();
            final int myHeight = getHeight();
            leftStrip.setBounds(Math.min(0, bounds.left - leftStrip.getIntrinsicWidth()),
                    myHeight - leftStrip.getIntrinsicHeight(), bounds.left, myHeight);
            rightStrip.setBounds(bounds.right, myHeight - rightStrip.getIntrinsicHeight(),
                    Math.max(getWidth(), bounds.right + rightStrip.getIntrinsicWidth()), myHeight);
            mStripMoved = false;
        }

        leftStrip.draw(canvas);
        rightStrip.draw(canvas);
    
public booleandispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        onPopulateAccessibilityEvent(event);
        // Dispatch only to the selected tab.
        if (mSelectedTab != -1) {
            View tabView = getChildTabViewAt(mSelectedTab);
            if (tabView != null && tabView.getVisibility() == VISIBLE) {
                return tabView.dispatchPopulateAccessibilityEvent(event);
            }
        }
        return false;
    
public voidfocusCurrentTab(int index)
Sets the current tab and focuses the UI on it. This method makes sure that the focused tab matches the selected tab, normally at {@link #setCurrentTab}. Normally this would not be an issue if we go through the UI, since the UI is responsible for calling TabWidget.onFocusChanged(), but in the case where we are selecting the tab programmatically, we'll need to make sure focus keeps up.

param
index The tab that you want focused (highlighted in orange) and selected (tab brought to the front of the widget)
see
#setCurrentTab

        final int oldTab = mSelectedTab;

        // set the tab
        setCurrentTab(index);

        // change the focus if applicable.
        if (oldTab != index) {
            getChildTabViewAt(index).requestFocus();
        }
    
protected intgetChildDrawingOrder(int childCount, int i)

        if (mSelectedTab == -1) {
            return i;
        } else {
            // Always draw the selected tab last, so that drop shadows are drawn
            // in the correct z-order.
            if (i == childCount - 1) {
                return mSelectedTab;
            } else if (i >= mSelectedTab) {
                return i + 1;
            } else {
                return i;
            }
        }
    
public android.view.ViewgetChildTabViewAt(int index)
Returns the tab indicator view at the given index.

param
index the zero-based index of the tab indicator view to return
return
the tab indicator view at the given index

        return getChildAt(index);
    
public intgetTabCount()
Returns the number of tab indicator views.

return
the number of tab indicator views.

        return getChildCount();
    
private voidinitTabWidget()

        setChildrenDrawingOrderEnabled(true);

        final Context context = mContext;

        // Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
        // in a values-v? directory which targets the current platform Sdk version instead.
        if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
            // Donut apps get old color scheme
            if (mLeftStrip == null) {
                mLeftStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_left_v4);
            }
            if (mRightStrip == null) {
                mRightStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_right_v4);
            }
        } else {
            // Use modern color scheme for Eclair and beyond
            if (mLeftStrip == null) {
                mLeftStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_left);
            }
            if (mRightStrip == null) {
                mRightStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_right);
            }
        }

        // Deal with focus, as we don't want the focus to go by default
        // to a tab other than the current tab
        setFocusable(true);
        setOnFocusChangeListener(this);
    
public booleanisStripEnabled()
Indicates whether the bottom strips on the tab indicators are drawn or not.

        return mDrawBottomStrips;
    
voidmeasureChildBeforeLayout(android.view.View child, int childIndex, int widthMeasureSpec, int totalWidth, int heightMeasureSpec, int totalHeight)

        if (!isMeasureWithLargestChildEnabled() && mImposedTabsHeight >= 0) {
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(
                    totalWidth + mImposedTabWidths[childIndex], MeasureSpec.EXACTLY);
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(mImposedTabsHeight,
                    MeasureSpec.EXACTLY);
        }

        super.measureChildBeforeLayout(child, childIndex,
                widthMeasureSpec, totalWidth, heightMeasureSpec, totalHeight);
    
voidmeasureHorizontal(int widthMeasureSpec, int heightMeasureSpec)

        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
            super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
            return;
        }

        // First, measure with no constraint
        final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        mImposedTabsHeight = -1;
        super.measureHorizontal(unspecifiedWidth, heightMeasureSpec);

        int extraWidth = getMeasuredWidth() - MeasureSpec.getSize(widthMeasureSpec);
        if (extraWidth > 0) {
            final int count = getChildCount();

            int childCount = 0;
            for (int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                if (child.getVisibility() == GONE) continue;
                childCount++;
            }

            if (childCount > 0) {
                if (mImposedTabWidths == null || mImposedTabWidths.length != count) {
                    mImposedTabWidths = new int[count];
                }
                for (int i = 0; i < count; i++) {
                    final View child = getChildAt(i);
                    if (child.getVisibility() == GONE) continue;
                    final int childWidth = child.getMeasuredWidth();
                    final int delta = extraWidth / childCount;
                    final int newWidth = Math.max(0, childWidth - delta);
                    mImposedTabWidths[i] = newWidth;
                    // Make sure the extra width is evenly distributed, no int division remainder
                    extraWidth -= childWidth - newWidth; // delta may have been clamped
                    childCount--;
                    mImposedTabsHeight = Math.max(mImposedTabsHeight, child.getMeasuredHeight());
                }
            }
        }

        // Measure again, this time with imposed tab widths and respecting initial spec request
        super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
    
public voidonFocusChange(android.view.View v, boolean hasFocus)
{@inheritDoc}

        if (v == this && hasFocus && getTabCount() > 0) {
            getChildTabViewAt(mSelectedTab).requestFocus();
            return;
        }

        if (hasFocus) {
            int i = 0;
            int numTabs = getTabCount();
            while (i < numTabs) {
                if (getChildTabViewAt(i) == v) {
                    setCurrentTab(i);
                    mSelectionChangedListener.onTabSelectionChanged(i, false);
                    if (isShown()) {
                        // a tab is focused so send an event to announce the tab widget state
                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
                    }
                    break;
                }
                i++;
            }
        }
    
public voidonInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)

        super.onInitializeAccessibilityEvent(event);
        event.setClassName(TabWidget.class.getName());
        event.setItemCount(getTabCount());
        event.setCurrentItemIndex(mSelectedTab);
    
public voidonInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)

        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(TabWidget.class.getName());
    
protected voidonSizeChanged(int w, int h, int oldw, int oldh)

        mStripMoved = true;
        super.onSizeChanged(w, h, oldw, oldh);
    
public voidremoveAllViews()

        super.removeAllViews();
        mSelectedTab = -1;
    
public voidsendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent event)

        // this class fires events only when tabs are focused or selected
        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
            event.recycle();
            return;
        }
        super.sendAccessibilityEventUnchecked(event);
    
public voidsetCurrentTab(int index)
Sets the current tab. This method is used to bring a tab to the front of the Widget, and is used to post to the rest of the UI that a different tab has been brought to the foreground. Note, this is separate from the traditional "focus" that is employed from the view logic. For instance, if we have a list in a tabbed view, a user may be navigating up and down the list, moving the UI focus (orange highlighting) through the list items. The cursor movement does not effect the "selected" tab though, because what is being scrolled through is all on the same tab. The selected tab only changes when we navigate between tabs (moving from the list view to the next tabbed view, in this example). To move both the focus AND the selected tab at once, please use {@link #setCurrentTab}. Normally, the view logic takes care of adjusting the focus, so unless you're circumventing the UI, you'll probably just focus your interest here.

param
index The tab that you want to indicate as the selected tab (tab brought to the front of the widget)
see
#focusCurrentTab

        if (index < 0 || index >= getTabCount() || index == mSelectedTab) {
            return;
        }

        if (mSelectedTab != -1) {
            getChildTabViewAt(mSelectedTab).setSelected(false);
        }
        mSelectedTab = index;
        getChildTabViewAt(mSelectedTab).setSelected(true);
        mStripMoved = true;

        if (isShown()) {
            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
        }
    
public voidsetDividerDrawable(android.graphics.drawable.Drawable drawable)
Sets the drawable to use as a divider between the tab indicators.

param
drawable the divider drawable

        super.setDividerDrawable(drawable);
    
public voidsetDividerDrawable(int resId)
Sets the drawable to use as a divider between the tab indicators.

param
resId the resource identifier of the drawable to use as a divider.

        setDividerDrawable(mContext.getDrawable(resId));
    
public voidsetEnabled(boolean enabled)

        super.setEnabled(enabled);

        final int count = getTabCount();
        for (int i = 0; i < count; i++) {
            View child = getChildTabViewAt(i);
            child.setEnabled(enabled);
        }
    
public voidsetLeftStripDrawable(android.graphics.drawable.Drawable drawable)
Sets the drawable to use as the left part of the strip below the tab indicators.

param
drawable the left strip drawable

        mLeftStrip = drawable;
        requestLayout();
        invalidate();
    
public voidsetLeftStripDrawable(int resId)
Sets the drawable to use as the left part of the strip below the tab indicators.

param
resId the resource identifier of the drawable to use as the left strip drawable

        setLeftStripDrawable(mContext.getDrawable(resId));
    
public voidsetRightStripDrawable(android.graphics.drawable.Drawable drawable)
Sets the drawable to use as the right part of the strip below the tab indicators.

param
drawable the right strip drawable

        mRightStrip = drawable;
        requestLayout();
        invalidate();
    
public voidsetRightStripDrawable(int resId)
Sets the drawable to use as the right part of the strip below the tab indicators.

param
resId the resource identifier of the drawable to use as the right strip drawable

        setRightStripDrawable(mContext.getDrawable(resId));
    
public voidsetStripEnabled(boolean stripEnabled)
Controls whether the bottom strips on the tab indicators are drawn or not. The default is to draw them. If the user specifies a custom view for the tab indicators, then the TabHost class calls this method to disable drawing of the bottom strips.

param
stripEnabled true if the bottom strips should be drawn.

        mDrawBottomStrips = stripEnabled;
        invalidate();
    
voidsetTabSelectionListener(android.widget.TabWidget$OnTabSelectionChanged listener)
Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.

        mSelectionChangedListener = listener;