Merge change 2900 into donut

* changes:
  Add support for custom tab views in TabHost and TabWidget.
This commit is contained in:
Android (Google) Code Review
2009-06-10 11:41:49 -07:00
3 changed files with 203 additions and 21 deletions

View File

@@ -46362,7 +46362,7 @@
</parameter> </parameter>
<parameter name="height" type="int"> <parameter name="height" type="int">
</parameter> </parameter>
<parameter name="edge" type="int"> <parameter name="inset" type="int">
</parameter> </parameter>
<parameter name="color" type="int"> <parameter name="color" type="int">
</parameter> </parameter>
@@ -173571,6 +173571,17 @@
deprecated="not deprecated" deprecated="not deprecated"
visibility="public" 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" <method name="setContent"
return="android.widget.TabHost.TabSpec" return="android.widget.TabHost.TabSpec"
abstract="false" abstract="false"
@@ -173638,6 +173649,19 @@
<parameter name="icon" type="android.graphics.drawable.Drawable"> <parameter name="icon" type="android.graphics.drawable.Drawable">
</parameter> </parameter>
</method> </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>
<class name="TabWidget" <class name="TabWidget"
extends="android.widget.LinearLayout" extends="android.widget.LinearLayout"
@@ -173711,6 +173735,30 @@
<parameter name="index" type="int"> <parameter name="index" type="int">
</parameter> </parameter>
</method> </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" <method name="onFocusChange"
return="void" return="void"
abstract="false" abstract="false"
@@ -173739,6 +173787,32 @@
<parameter name="index" type="int"> <parameter name="index" type="int">
</parameter> </parameter>
</method> </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>
<class name="TableLayout" <class name="TableLayout"
extends="android.widget.LinearLayout" extends="android.widget.LinearLayout"

View File

@@ -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 // leaving touch mode.. if nothing has focus, let's give it to
// the indicator of the current tab // the indicator of the current tab
if (!mCurrentView.hasFocus() || mCurrentView.isFocused()) { 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(); View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
tabIndicator.setOnKeyListener(mTabKeyListener); 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); mTabWidget.addView(tabIndicator);
mTabSpecs.add(tabSpec); mTabSpecs.add(tabSpec);
@@ -235,7 +241,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
public View getCurrentTabView() { public View getCurrentTabView() {
if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) { if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
return mTabWidget.getChildAt(mCurrentTab); return mTabWidget.getChildTabViewAt(mCurrentTab);
} }
return null; return null;
} }
@@ -273,7 +279,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
&& (mCurrentView.isRootNamespace()) && (mCurrentView.isRootNamespace())
&& (mCurrentView.hasFocus()) && (mCurrentView.hasFocus())
&& (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null)) { && (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null)) {
mTabWidget.getChildAt(mCurrentTab).requestFocus(); mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
playSoundEffect(SoundEffectConstants.NAVIGATION_UP); playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
return true; return true;
} }
@@ -410,6 +416,14 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
return this; 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 * Specify the id of the view that should be used as the content
* of the tab. * of the tab.
@@ -437,7 +451,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
} }
String getTag() { public String getTag() {
return mTag; 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. * How to create the tab content via a view id.
*/ */

View File

@@ -49,6 +49,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
private Drawable mBottomLeftStrip; private Drawable mBottomLeftStrip;
private Drawable mBottomRightStrip; private Drawable mBottomRightStrip;
private boolean mStripMoved; private boolean mStripMoved;
private Drawable mDividerDrawable;
private boolean mDrawBottomStrips = true;
public TabWidget(Context context) { public TabWidget(Context context) {
this(context, null); this(context, null);
@@ -87,9 +89,68 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
setOnFocusChangeListener(this); 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 @Override
public void childDrawableStateChanged(View child) { public void childDrawableStateChanged(View child) {
if (child == getChildAt(mSelectedTab)) { if (child == getChildTabViewAt(mSelectedTab)) {
// To make sure that the bottom strip is redrawn // To make sure that the bottom strip is redrawn
invalidate(); invalidate();
} }
@@ -100,7 +161,14 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
public void dispatchDraw(Canvas canvas) { public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(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()); mBottomLeftStrip.setState(selectedChild.getDrawableState());
mBottomRightStrip.setState(selectedChild.getDrawableState()); mBottomRightStrip.setState(selectedChild.getDrawableState());
@@ -157,13 +225,13 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
* @see #focusCurrentTab * @see #focusCurrentTab
*/ */
public void setCurrentTab(int index) { public void setCurrentTab(int index) {
if (index < 0 || index >= getChildCount()) { if (index < 0 || index >= getTabCount()) {
return; return;
} }
getChildAt(mSelectedTab).setSelected(false); getChildTabViewAt(mSelectedTab).setSelected(false);
mSelectedTab = index; mSelectedTab = index;
getChildAt(mSelectedTab).setSelected(true); getChildTabViewAt(mSelectedTab).setSelected(true);
mStripMoved = true; mStripMoved = true;
} }
@@ -189,17 +257,17 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
// change the focus if applicable. // change the focus if applicable.
if (oldTab != index) { if (oldTab != index) {
getChildAt(index).requestFocus(); getChildTabViewAt(index).requestFocus();
} }
} }
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
super.setEnabled(enabled); super.setEnabled(enabled);
int count = getChildCount(); int count = getTabCount();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
View child = getChildAt(i); View child = getChildTabViewAt(i);
child.setEnabled(enabled); child.setEnabled(enabled);
} }
} }
@@ -218,17 +286,26 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
child.setFocusable(true); child.setFocusable(true);
child.setClickable(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); super.addView(child);
// TODO: detect this via geometry with a tabwidget listener rather // TODO: detect this via geometry with a tabwidget listener rather
// than potentially interfere with the view's listener // than potentially interfere with the view's listener
child.setOnClickListener(new TabClickListener(getChildCount() - 1)); child.setOnClickListener(new TabClickListener(getTabCount() - 1));
child.setOnFocusChangeListener(this); child.setOnFocusChangeListener(this);
} }
/** /**
* Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator. * 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) { public void onFocusChange(View v, boolean hasFocus) {
if (v == this && hasFocus) { if (v == this && hasFocus) {
getChildAt(mSelectedTab).requestFocus(); getChildTabViewAt(mSelectedTab).requestFocus();
return; return;
} }
if (hasFocus) { if (hasFocus) {
int i = 0; int i = 0;
while (i < getChildCount()) { int numTabs = getTabCount();
if (getChildAt(i) == v) { while (i < numTabs) {
if (getChildTabViewAt(i) == v) {
setCurrentTab(i); setCurrentTab(i);
mSelectionChangedListener.onTabSelectionChanged(i, false); mSelectionChangedListener.onTabSelectionChanged(i, false);
break; break;