Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53175148 authored by Jack Veenstra's avatar Jack Veenstra
Browse files

Add support for custom tab views in TabHost and TabWidget.

This change adds the ability to specify an arbitrary view for a tab
indicator.  It also adds support for specifying a drawable to use as
the divider between tab views.
parent a32b5f32
Loading
Loading
Loading
Loading
+75 −1
Original line number Diff line number Diff line
@@ -46362,7 +46362,7 @@
</parameter>
<parameter name="height" type="int">
</parameter>
<parameter name="edge" type="int">
<parameter name="inset" type="int">
</parameter>
<parameter name="color" type="int">
</parameter>
@@ -173571,6 +173571,17 @@
 deprecated="not deprecated"
 visibility="public"
>
<method name="getTag"
 return="java.lang.String"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="setContent"
 return="android.widget.TabHost.TabSpec"
 abstract="false"
@@ -173638,6 +173649,19 @@
<parameter name="icon" type="android.graphics.drawable.Drawable">
</parameter>
</method>
<method name="setIndicator"
 return="android.widget.TabHost.TabSpec"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="view" type="android.view.View">
</parameter>
</method>
</class>
<class name="TabWidget"
 extends="android.widget.LinearLayout"
@@ -173711,6 +173735,30 @@
<parameter name="index" type="int">
</parameter>
</method>
<method name="getChildTabViewAt"
 return="android.view.View"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="index" type="int">
</parameter>
</method>
<method name="getTabCount"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="onFocusChange"
 return="void"
 abstract="false"
@@ -173739,6 +173787,32 @@
<parameter name="index" type="int">
</parameter>
</method>
<method name="setDividerDrawable"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="drawable" type="android.graphics.drawable.Drawable">
</parameter>
</method>
<method name="setDividerDrawable"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="resId" type="int">
</parameter>
</method>
</class>
<class name="TableLayout"
 extends="android.widget.LinearLayout"
+34 −4
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
            // leaving touch mode.. if nothing has focus, let's give it to
            // the indicator of the current tab
            if (!mCurrentView.hasFocus() || mCurrentView.isFocused()) {
                mTabWidget.getChildAt(mCurrentTab).requestFocus();
                mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
            }
        }
    }
@@ -197,6 +197,12 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
        }
        View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
        tabIndicator.setOnKeyListener(mTabKeyListener);

        // If this is a custom view, then do not draw the bottom strips for
        // the tab indicators.
        if (tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy) {
            mTabWidget.setDrawBottomStrips(false);
        }
        mTabWidget.addView(tabIndicator);
        mTabSpecs.add(tabSpec);

@@ -235,7 +241,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");

    public View getCurrentTabView() {
        if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
            return mTabWidget.getChildAt(mCurrentTab);
            return mTabWidget.getChildTabViewAt(mCurrentTab);
        }
        return null;
    }
@@ -273,7 +279,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
                && (mCurrentView.isRootNamespace())
                && (mCurrentView.hasFocus())
                && (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null)) {
            mTabWidget.getChildAt(mCurrentTab).requestFocus();
            mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
            playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
            return true;
        }
@@ -410,6 +416,14 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
            return this;
        }

        /**
         * Specify a view as the tab indicator.
         */
        public TabSpec setIndicator(View view) {
            mIndicatorStrategy = new ViewIndicatorStrategy(view);
            return this;
        }

        /**
         * Specify the id of the view that should be used as the content
         * of the tab.
@@ -437,7 +451,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
        }


        String getTag() {
        public String getTag() {
            return mTag;
        }
    }
@@ -525,6 +539,22 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
        }
    }

    /**
     * How to create a tab indicator by specifying a view.
     */
    private class ViewIndicatorStrategy implements IndicatorStrategy {

        private final View mView;

        private ViewIndicatorStrategy(View view) {
            mView = view;
        }

        public View createIndicatorView() {
            return mView;
        }
    }

    /**
     * How to create the tab content via a view id.
     */
+94 −16
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    private Drawable mBottomLeftStrip;
    private Drawable mBottomRightStrip;
    private boolean mStripMoved;
    private Drawable mDividerDrawable;
    private boolean mDrawBottomStrips = true;

    public TabWidget(Context context) {
        this(context, null);
@@ -87,9 +89,68 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
        setOnFocusChangeListener(this);
    }

    /**
     * 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
     */
    public View getChildTabViewAt(int index) {
        // If we are using dividers, then instead of tab views at 0, 1, 2, ...
        // we have tab views at 0, 2, 4, ...
        if (mDividerDrawable != null) {
            index *= 2;
        }
        return getChildAt(index);
    }

    /**
     * Returns the number of tab indicator views.
     * @return the number of tab indicator views.
     */
    public int getTabCount() {
        int children = getChildCount();

        // If we have dividers, then we will always have an odd number of
        // children: 1, 3, 5, ... and we want to convert that sequence to
        // this: 1, 2, 3, ...
        if (mDividerDrawable != null) {
            children = (children + 1) / 2;
        }
        return children;
    }

    /**
     * Sets the drawable to use as a divider between the tab indicators.
     * @param drawable the divider drawable
     */
    public void setDividerDrawable(Drawable drawable) {
        mDividerDrawable = drawable;
    }

    /**
     * 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.
     */
    public void setDividerDrawable(int resId) {
        mDividerDrawable = mContext.getResources().getDrawable(resId);
    }

    /**
     * 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 drawBottomStrips true if the bottom strips should be drawn.
     */
    void setDrawBottomStrips(boolean drawBottomStrips) {
        mDrawBottomStrips = drawBottomStrips;
    }

    @Override
    public void childDrawableStateChanged(View child) {
        if (child == getChildAt(mSelectedTab)) {
        if (child == getChildTabViewAt(mSelectedTab)) {
            // To make sure that the bottom strip is redrawn
            invalidate();
        }
@@ -100,7 +161,14 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    public void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);

        View selectedChild = getChildAt(mSelectedTab);
        // 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;
        }

        View selectedChild = getChildTabViewAt(mSelectedTab);
        
        mBottomLeftStrip.setState(selectedChild.getDrawableState());
        mBottomRightStrip.setState(selectedChild.getDrawableState());
@@ -157,13 +225,13 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
     *  @see #focusCurrentTab
     */
    public void setCurrentTab(int index) {
        if (index < 0 || index >= getChildCount()) {
        if (index < 0 || index >= getTabCount()) {
            return;
        }

        getChildAt(mSelectedTab).setSelected(false);
        getChildTabViewAt(mSelectedTab).setSelected(false);
        mSelectedTab = index;
        getChildAt(mSelectedTab).setSelected(true);
        getChildTabViewAt(mSelectedTab).setSelected(true);
        mStripMoved = true;
    }
    
@@ -189,17 +257,17 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
        
        // change the focus if applicable.
        if (oldTab != index) {
            getChildAt(index).requestFocus();
            getChildTabViewAt(index).requestFocus();
        }
    }
    
    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        int count = getChildCount();
        int count = getTabCount();
        
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            View child = getChildTabViewAt(i);
            child.setEnabled(enabled);
        }
    }
@@ -218,17 +286,26 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
        child.setFocusable(true);
        child.setClickable(true);

        // If we have dividers between the tabs and we already have at least one
        // tab, then add a divider before adding the next tab.
        if (mDividerDrawable != null && getTabCount() > 0) {
            View divider = new View(mContext);
            final LinearLayout.LayoutParams lp = new LayoutParams(
                    mDividerDrawable.getIntrinsicWidth(),
                    mDividerDrawable.getIntrinsicHeight());
            lp.setMargins(0, 0, 0, 0);
            divider.setLayoutParams(lp);
            divider.setBackgroundDrawable(mDividerDrawable);
            super.addView(divider);
        }
        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(getChildCount() - 1));
        child.setOnClickListener(new TabClickListener(getTabCount() - 1));
        child.setOnFocusChangeListener(this);
    }




    /**
     * Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.
     */
@@ -238,14 +315,15 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {

    public void onFocusChange(View v, boolean hasFocus) {
        if (v == this && hasFocus) {
            getChildAt(mSelectedTab).requestFocus();
            getChildTabViewAt(mSelectedTab).requestFocus();
            return;
        }
        
        if (hasFocus) {
            int i = 0;
            while (i < getChildCount()) {
                if (getChildAt(i) == v) {
            int numTabs = getTabCount();
            while (i < numTabs) {
                if (getChildTabViewAt(i) == v) {
                    setCurrentTab(i);
                    mSelectionChangedListener.onTabSelectionChanged(i, false);
                    break;