Activity
public class MyTabActivity extends ActivityGroup
{
private MyTabHost mTabHost;
private String mDefaultTab = null;
private int mDefaultTabIndex = -1;
/**
* Sets the default tab that is the first tab highlighted.
*
* @param tag the name of the default tab
*/
public void setDefaultTab(String tag)
{
mDefaultTab = tag;
mDefaultTabIndex = -1;
}
/**
* Sets the default tab that is the first tab highlighted.
*
* @param index the index of the default tab
*/
public void setDefaultTab(int index)
{
mDefaultTab = null;
mDefaultTabIndex = index;
}
/**
* onRestoreInstanceState
*
* @param state Bundle
* @see android.app.Activity#onRestoreInstanceState(android.os.Bundle)
*/
@Override
protected void onRestoreInstanceState(Bundle state)
{
super.onRestoreInstanceState(state);
ensureTabHost();
String cur = state.getString("currentTab");
if (cur != null)
{
mTabHost.setCurrentTabByTag(cur);
}
if (mTabHost.getCurrentTab() < 0)
{
if (mDefaultTab != null)
{
mTabHost.setCurrentTabByTag(mDefaultTab);
}
else if (mDefaultTabIndex >= 0)
{
mTabHost.setCurrentTab(mDefaultTabIndex);
}
}
}
/**
*
* onPostCreate
*
* @param icicle Bundle
* @see android.app.Activity#onPostCreate(android.os.Bundle)
*/
@Override
protected void onPostCreate(Bundle icicle)
{
super.onPostCreate(icicle);
ensureTabHost();
if (mTabHost.getCurrentTab() == -1)
{
mTabHost.setCurrentTab(0);
}
}
/**
*
* onSaveInstanceState
*
* @param outState Bundle
* @see android.app.ActivityGroup#onSaveInstanceState(android.os.Bundle)
*/
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
String currentTabTag = mTabHost.getCurrentTabTag();
if (currentTabTag != null)
{
outState.putString("currentTab", currentTabTag);
}
}
/**
* Updates the screen state (current list and other views) when the content
* changes.
*
*@see Activity#onContentChanged()
*/
@Override
public void onContentChanged()
{
super.onContentChanged();
mTabHost = (MyTabHost) findViewById(R.id.tabhost);
if (mTabHost == null)
{
throw new RuntimeException(
"Your content must have a TabHost whose id attribute is "
+ "'R.id.tabhost'");
}
mTabHost.setup(getLocalActivityManager());
}
private void ensureTabHost()
{
if (mTabHost == null)
{
this.setContentView(R.layout.tab_content);
}
}
/**
*
* onChildTitleChanged
*
* @param childActivity Activity
* @param title CharSequence
* @see android.app.Activity#onChildTitleChanged(android.app.Activity,
* java.lang.CharSequence)
*/
@Override
protected void onChildTitleChanged(Activity childActivity,
CharSequence title)
{
// Dorky implementation until we can have multiple activities running.
if (getLocalActivityManager().getCurrentActivity() == childActivity)
{
View tabView = mTabHost.getCurrentTabView();
if (tabView != null && tabView instanceof TextView)
{
((TextView) tabView).setText(title);
}
}
}
/**
* Returns the {@link TabHost} the activity is using to host its tabs.
*
* @return the {@link TabHost} the activity is using to host its tabs.
*/
public MyTabHost getTabHost()
{
ensureTabHost();
return mTabHost;
}
/**
* Returns the {@link TabWidget} the activity is using to draw the actual
* tabs.
*
* @return the {@link TabWidget} the activity is using to draw the actual
* tabs.
*/
public MyTabWidget getTabWidget()
{
return mTabHost.getTabWidgetT();
}
}
Host:
public class MyTabHost extends FrameLayout implements OnTouchModeChangeListener
{
private MyTabWidget mTabWidget;
private FrameLayout mTabContent;
private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
/**
* 子TAB标志
*/
private boolean isParent = true;
/**
* This field should be made private, so it is hidden from the SDK.
*/
private View mCurrentView = null;
/**
* This field should be made private, so it is hidden from the SDK.
*/
private OnTabChangeListener mOnTabChangeListener;
private OnKeyListener mTabKeyListener;
private int mCurrentTab = -1;
private LocalActivityManager mLocalActivityManager = null;
/**
* @param context Context
*/
public MyTabHost(Context context)
{
super(context);
initTabHost();
}
/**
* @param context Context
* @param attrs AttributeSet
*/
public MyTabHost(Context context, AttributeSet attrs)
{
super(context, attrs);
initTabHost();
}
private final void initTabHost()
{
setFocusableInTouchMode(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
mCurrentTab = -1;
mCurrentView = null;
}
/**
*
* newTabSpecT
*
* @param tag String
* @return TabSpec
*/
public TabSpec newTabSpecT(String tag)
{
return new TabSpec(tag);
}
/**
* <p>
* Call setup() before adding tabs if loading TabHost using findViewById().
* <i><b>However</i></b>: You do not need to call setup() after getTabHost()
* in {@link android.app.TabActivity TabActivity}. Example:
* </p>
*
* <pre>
* mTabHost = (TabHost) findViewById(R.id.tabhost);
* mTabHost.setup();
* mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
*/
public void setup()
{
mTabWidget = (MyTabWidget) findViewById(R.id.tabs);
if (mTabWidget == null)
{
throw new RuntimeException(
"Your TabHost must have a TabWidget whose id attribute is 'R.id.tabs'");
}
// KeyListener to attach to all tabs. Detects non-navigation keys
// and relays them to the tab content.
mTabKeyListener = new OnKeyListener()
{
public boolean onKey(View v, int keyCode, KeyEvent event)
{
switch (keyCode)
{
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_ENTER:
return false;
}
mTabContent.requestFocus(View.FOCUS_FORWARD);
return mTabContent.dispatchKeyEvent(event);
}
};
mTabWidget
.setTabSelectionListener(new MyTabWidget.OnTabSelectionChanged()
{
public void onTabSelectionChanged(int tabIndex, boolean clicked)
{
setCurrentTab(tabIndex);
if (clicked)
{
mTabContent.requestFocus(View.FOCUS_FORWARD);
}
}
});
mTabContent = (FrameLayout) findViewById(R.id.tabcontent);
if (mTabContent == null)
{
throw new RuntimeException("Your TabHost must have a FrameLayout"
+ " whose id attribute is 'android.R.id.tabcontent'");
}
}
/**
* If you are using {@link TabSpec#setContent(android.content.Intent)}, this
* must be called since the activityGroup is needed to launch the local
* activity.
*
* This is done for you if you extend {@link android.app.TabActivity}.
*
* @param activityGroup Used to launch activities for tab content.
*/
public void setup(LocalActivityManager activityGroup)
{
setup();
mLocalActivityManager = activityGroup;
}
/**
*
* onAttachedToWindow
*
* @see android.widget.TabHost#onAttachedToWindow()
*/
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
if (treeObserver != null)
{
treeObserver.addOnTouchModeChangeListener(this);
}
}
/**
*
* onDetachedFromWindow
*
* @see android.widget.TabHost#onDetachedFromWindow()
*/
@Override
protected void onDetachedFromWindow()
{
super.onDetachedFromWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
if (treeObserver != null)
{
treeObserver.removeOnTouchModeChangeListener(this);
}
}
/**
* {@inheritDoc}
*/
public void onTouchModeChanged(boolean isInTouchMode)
{
if (!isInTouchMode)
{
// 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();
}
}
}
/**
* Add a tab.
*
* @param tabSpec Specifies how to create the indicator and content.
*/
public void addTab(TabSpec tabSpec)
{
if (tabSpec.mIndicatorStrategy == null)
{
throw new IllegalArgumentException(
"you must specify a way to create the tab indicator.");
}
if (tabSpec.mContentStrategy == null)
{
throw new IllegalArgumentException(
"you must specify a way to create the tab content");
}
View tabIndicator = tabSpec.mIndicatorStrategy.createIndicatorView();
tabIndicator.setOnKeyListener(mTabKeyListener);
mTabWidget.addView(tabIndicator);
mTabSpecs.add(tabSpec);
// 初始化时,设置默认选中tabIndex = 1;
if (mCurrentTab == -1)
{
setCurrentTab(1);
}
}
/**
* Removes all tabs from the tab widget associated with this tab host.
*/
public void clearAllTabs()
{
mTabWidget.removeAllViews();
initTabHost();
mTabContent.removeAllViews();
mTabSpecs.clear();
requestLayout();
invalidate();
}
public MyTabWidget getTabWidgetT()
{
return mTabWidget;
}
public int getCurrentTab()
{
return mCurrentTab;
}
/**
*
* getCurrentTabTag
*
* @return String
* @see android.widget.TabHost#getCurrentTabTag()
*/
public String getCurrentTabTag()
{
if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size())
{
return mTabSpecs.get(mCurrentTab).getTag();
}
return null;
}
/**
*
* getCurrentTabView
*
* @return View
* @see android.widget.TabHost#getCurrentTabView()
*/
public View getCurrentTabView()
{
if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size())
{
return mTabWidget.getChildAt(mCurrentTab);
}
return null;
}
public View getCurrentView()
{
return mCurrentView;
}
/**
*
* setCurrentTabByTag
*
* @param tag aa
* @see android.widget.TabHost#setCurrentTabByTag(java.lang.String)
*/
public void setCurrentTabByTag(String tag)
{
int i;
for (i = 0; i < mTabSpecs.size(); i++)
{
if (mTabSpecs.get(i).getTag().equals(tag))
{
setCurrentTab(i);
break;
}
}
}
/**
*
* getTabContentView
*
* @return FrameLayout
* @see android.widget.TabHost#getTabContentView()
*/
public FrameLayout getTabContentView()
{
return mTabContent;
}
/**
*
* dispatchKeyEvent
*
* @param event KeyEvent
* @return boolean
* @see android.widget.TabHost#dispatchKeyEvent(android.view.KeyEvent)
*/
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
boolean handled = false;
try
{
handled = super.dispatchKeyEvent(event);
// unhandled key ups change focus to tab indicator for embedded
// activities
// when there is nothing that will take focus from default focus
// searching
if (!handled
&& (event.getAction() == KeyEvent.ACTION_DOWN)
&& (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP)
&& (mCurrentView.hasFocus())
&& (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null))
{
mTabWidget.getChildAt(mCurrentTab).requestFocus();
playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
return true;
}
}
catch (Exception e)
{
e.printStackTrace();
// Log.w("not focuse",
// e.getMessage());
}
return handled;
}
/**
*
* dispatchWindowFocusChanged
*
* @param hasFocus boolean
* @see android.widget.TabHost#dispatchWindowFocusChanged(boolean)
*/
@Override
public void dispatchWindowFocusChanged(boolean hasFocus)
{
mCurrentView.dispatchWindowFocusChanged(hasFocus);
}
/**
*
* setCurrentTab
*
* @param index int
* @see android.widget.TabHost#setCurrentTab(int)
*/
public void setCurrentTab(int index)
{
if (index < 0 || index >= mTabSpecs.size())
{
return;
}
if (index == mCurrentTab)
{
return;
}
// notify old tab content
if (mCurrentTab != -1)
{
mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();
}
mCurrentTab = index;
final MyTabHost.TabSpec spec = mTabSpecs.get(index);
// Call the tab widget's focusCurrentTab(), instead of just
// selecting the tab.
mTabWidget.focusCurrentTab(mCurrentTab);
// tab content
mCurrentView = spec.mContentStrategy.getContentView();
if (mCurrentView.getParent() == null)
{
mTabContent.addView(mCurrentView, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
}
if (!mTabWidget.hasFocus())
{
// if the tab widget didn't take focus (likely because we're in
// touch mode)
// give the current tab content view a shot
mCurrentView.requestFocus();
}
// mTabContent.requestFocus(View.FOCUS_FORWARD);
invokeOnTabChangeListener();
}
/**
* Register a callback to be invoked when the selected state of any of the
* items in this list changes
*
* @param l The callback that will run
*/
public void setOnTabChangedListener(OnTabChangeListener l)
{
mOnTabChangeListener = l;
}
private void invokeOnTabChangeListener()
{
if (mOnTabChangeListener != null)
{
mOnTabChangeListener.onTabChanged(getCurrentTabTag());
}
}
/**
* Interface definition for a callback to be invoked when tab changed
*/
public interface OnTabChangeListener
{
/**
* onTabChanged
*
* @param tabId String
*/
void onTabChanged(String tabId);
}
/**
* Makes the content of a tab when it is selected. Use this if your tab
* content needs to be created on demand, i.e. you are not showing an
* existing view or starting an activity.
*/
public interface TabContentFactory
{
/**
* Callback to make the tab contents
*
* @param tag Which tab was selected.
* @return The view to distplay the contents of the selected tab.
*/
View createTabContent(String tag);
}
/**
* A tab has a tab indictor, content, and a tag that is used to keep track
* of it. This builder helps choose among these options.
*
* For the tab indicator, your choices are: 1) set a label 2) set a label
* and an icon
*
* For the tab content, your choices are: 1) the id of a {@link View} 2) a
* {@link TabContentFactory} that creates the {@link View} content. 3) an
* {@link Intent} that launches an {@link android.app.Activity}.
*/
public class TabSpec
{
private String mTag;
private IndicatorStrategy mIndicatorStrategy;
private ContentStrategy mContentStrategy;
private TabSpec(String tag)
{
mTag = tag;
}
/**
*
* setIndicator
*
* @param label CharSequence
* @return TabSpec
*/
public TabSpec setIndicator(CharSequence label)
{
mIndicatorStrategy = new LabelIndicatorStrategy(label);
return this;
}
/**
*
* setIndicator
*
* @param label CharSequence
* @param icon Drawable
* @return TabSpec
*/
public TabSpec setIndicator(CharSequence label, Drawable icon)
{
mIndicatorStrategy = new LabelAndIconIndicatorStrategy(label, icon);
return this;
}
/**
* setContent
*
* @param viewId int
* @return TabSpec
*/
public TabSpec setContent(int viewId)
{
mContentStrategy = new ViewIdContentStrategy(viewId);
return this;
}
/**
* setContent
*
* @param contentFactory TabContentFactory
* @return TabSpec
*/
public TabSpec setContent(TabContentFactory contentFactory)
{
mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);
return this;
}
/**
* setContent
*
* @param intent Intent
* @return TabSpec
*/
public TabSpec setContent(Intent intent)
{
mContentStrategy = new IntentContentStrategy(mTag, intent);
return this;
}
String getTag()
{
return mTag;
}
}
/**
* Specifies what you do to create a tab indicator.
*/
private static interface IndicatorStrategy
{
/**
* Return the view for the indicator.
*/
View createIndicatorView();
}
/**
* Specifies what you do to manage the tab content.
*/
private static interface ContentStrategy
{
/**
* Return the content view. The view should may be cached locally.
*/
View getContentView();
/**
* Perhaps do something when the tab associated with this content has
* been closed (i.e make it invisible, or remove it).
*/
void tabClosed();
}
/**
* How to create a tab indicator that just has a label.
*/
private class LabelIndicatorStrategy implements IndicatorStrategy
{
private final CharSequence mLabel;
private LabelIndicatorStrategy(CharSequence label)
{
mLabel = label;
}
public View createIndicatorView()
{
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int tabInd = isParent ? R.layout.tab_indicator
: R.layout.tab_indicator_child;
View tabIndicator = inflater.inflate(tabInd, mTabWidget, // tab widget is the parent
false); // no inflate params
if (isParent)
{
tabIndicator.setBackgroundResource(R.drawable.tab_indicator);
}
else
{
tabIndicator.setBackgroundResource(R.drawable.tab_indicator);
}
final TextView tv = (TextView) tabIndicator
.findViewById(R.id.title);
tv.setText(mLabel);
return tabIndicator;
}
}
/**
* How we create a tab indicator that has a label and an icon
*/
private class LabelAndIconIndicatorStrategy implements IndicatorStrategy
{
private final CharSequence mLabel;
private final Drawable mIcon;
private LabelAndIconIndicatorStrategy(CharSequence label, Drawable icon)
{
mLabel = label;
mIcon = icon;
}
public View createIndicatorView()
{
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View tabIndicator = inflater.inflate(R.layout.tab_indicator,
mTabWidget, // tab widget is the parent
false); // no inflate params
tabIndicator.setBackgroundResource(R.drawable.tab_indicator);
final TextView tv = (TextView) tabIndicator
.findViewById(R.id.title);
tv.setText(mLabel);
final ImageView iconView = (ImageView) tabIndicator
.findViewById(R.id.icon);
iconView.setImageDrawable(mIcon);
return tabIndicator;
}
}
/**
* How to create the tab content via a view id.
*/
private class ViewIdContentStrategy implements ContentStrategy
{
private final View mView;
private ViewIdContentStrategy(int viewId)
{
mView = mTabContent.findViewById(viewId);
if (mView != null)
{
mView.setVisibility(View.GONE);
}
else
{
throw new RuntimeException(
"Could not create tab content because "
+ "could not find view with id " + viewId);
}
}
public View getContentView()
{
mView.setVisibility(View.VISIBLE);
return mView;
}
public void tabClosed()
{
mView.setVisibility(View.GONE);
}
}
/**
* How tab content is managed using {@link TabContentFactory}.
*/
private class FactoryContentStrategy implements ContentStrategy
{
private View mTabContent;
private final CharSequence mTag;
private TabContentFactory mFactory;
public FactoryContentStrategy(CharSequence tag,
TabContentFactory factory)
{
mTag = tag;
mFactory = factory;
}
public View getContentView()
{
if (mTabContent == null)
{
mTabContent = mFactory.createTabContent(mTag.toString());
}
mTabContent.setVisibility(View.VISIBLE);
return mTabContent;
}
public void tabClosed()
{
mTabContent.setVisibility(View.INVISIBLE);
}
}
/**
* How tab content is managed via an {@link Intent}: the content view is the
* decorview of the launched activity.
*/
private class IntentContentStrategy implements ContentStrategy
{
private final String mTag;
private final Intent mIntent;
private View mLaunchedView;
private IntentContentStrategy(String tag, Intent intent)
{
mTag = tag;
mIntent = intent;
}
public View getContentView()
{
if (mLocalActivityManager == null)
{
throw new IllegalStateException(
"Did you forget to call 'public void "
+ "setup(LocalActivityManager activityGroup)'?");
}
final Window w = mLocalActivityManager.startActivity(mTag, mIntent);
final View wd = w != null ? w.getDecorView() : null;
if (mLaunchedView != wd && mLaunchedView != null)
{
if (mLaunchedView.getParent() != null)
{
mTabContent.removeView(mLaunchedView);
}
}
mLaunchedView = wd;
// XXX Set FOCUS_AFTER_DESCENDANTS on embedded activies for now so
// they can get
// focus if none of their children have it. They need focus to be
// able to
// display menu items.
//
// Replace this with something better when Bug 628886 is fixed...
//
if (mLaunchedView != null)
{
mLaunchedView.setVisibility(View.VISIBLE);
mLaunchedView.setFocusableInTouchMode(true);
((ViewGroup) mLaunchedView)
.setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
}
return mLaunchedView;
}
public void tabClosed()
{
if (mLaunchedView != null)
{
mLaunchedView.setVisibility(View.GONE);
}
}
}
/**
* 设置是否是父tab
*
* @param isP boolean
*/
public void setIsParent(boolean isP)
{
isParent = isP;
}
Widget:
public class MyTabWidget extends LinearLayout implements OnFocusChangeListener
{
private OnTabSelectionChanged mSelectionChangedListener;
private int mSelectedTab = 0;
/**
*
* @param context Context
*/
public MyTabWidget(Context context)
{
this(context, null);
}
/**
*
* @param context Context
* @param attrs AttributeSet
*/
public MyTabWidget(Context context, AttributeSet attrs)
{
this(context, attrs, com.android.internal.R.attr.tabWidgetStyle);
}
/**
*
* @param context Context
* @param attrs AttributeSet
* @param defStyle int
*/
public MyTabWidget(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs);
initTabWidget();
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.TabWidget, defStyle, 0);
a.recycle();
}
/**
*
*
*
* @param w int
* @param h int
* @param oldw int
* @param oldh int
* @see android.view.View#onSizeChanged(int, int, int, int)
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
}
private void initTabWidget()
{
setOrientation(LinearLayout.HORIZONTAL);
// mBottomLeftStrip = mContext
// .getResources()
// .getDrawable(com.android.internal.R.drawable.tab_bottom_left);
// mBottomRightStrip = mContext
// .getResources()
// .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);
}
/**
*
*
*
* @param child View
* @see android.view.ViewGroup#childDrawableStateChanged(android.view.View)
*/
@Override
public void childDrawableStateChanged(View child)
{
if (child == getChildAt(mSelectedTab))
{
// To make sure that the bottom strip is redrawn
invalidate();
}
super.childDrawableStateChanged(child);
}
/**
*
* 屏蔽了底下的线
*
* @param canvas Canvas
* @see android.view.ViewGroup#dispatchDraw(android.graphics.Canvas)
*/
@Override
public void dispatchDraw(Canvas canvas)
{
super.dispatchDraw(canvas);
}
/**
* 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
*/
public void setCurrentTab(int index)
{
if (index < 0 || index >= getChildCount())
{
return;
}
getChildAt(mSelectedTab).setSelected(false);
mSelectedTab = index;
getChildAt(mSelectedTab).setSelected(true);
}
/**
* 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
*/
public void focusCurrentTab(int index)
{
final int oldTab = mSelectedTab;
// set the tab
setCurrentTab(index);
// change the focus if applicable.
if (oldTab != index)
{
getChildAt(index).requestFocus();
}
}
/**
*
*
*
* @param enabled boolean
* @see android.view.View#setEnabled(boolean)
*/
@Override
public void setEnabled(boolean enabled)
{
super.setEnabled(enabled);
int count = getChildCount();
for (int i = 0; i < count; i++)
{
View child = getChildAt(i);
child.setEnabled(enabled);
}
}
/**
*
*
*
* @param child View
* @see android.view.ViewGroup#addView(android.view.View)
*/
@Override
public void addView(View child)
{
if (child.getLayoutParams() == null)
{
final LinearLayout.LayoutParams lp = new LayoutParams(0,
ViewGroup.LayoutParams.WRAP_CONTENT, 1);
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);
// than potentially interfere with the view's listener
child.setOnClickListener(new TabClickListener(getChildCount() - 1));
child.setOnFocusChangeListener(this);
}
/**
* Provides a way for {@link TabHost} to be notified that the user clicked
* on a tab indicator.
*/
void setTabSelectionListener(OnTabSelectionChanged listener)
{
mSelectionChangedListener = listener;
}
/**
*
*
*
* @param v View
* @param hasFocus boolean
* @see android.view.View.OnFocusChangeListener#onFocusChange(android.view.View,
* boolean)
*/
public void onFocusChange(View v, boolean hasFocus)
{
if (v == this && hasFocus)
{
getChildAt(mSelectedTab).requestFocus();
return;
}
if (hasFocus)
{
int i = 0;
while (i < getChildCount())
{
if (getChildAt(i) == v)
{
setCurrentTab(i);
mSelectionChangedListener.onTabSelectionChanged(i, false);
break;
}
i++;
}
}
}
// registered with each tab indicator so we can notify tab host
/**
*
* TabClickListener
*
* @version [MTVClient_Handset_R001C08L0ZT05, 2010-10-23]
*/
private class TabClickListener implements OnClickListener
{
private final int mTabIndex;
private TabClickListener(int tabIndex)
{
mTabIndex = tabIndex;
}
public void onClick(View v)
{
mSelectionChangedListener.onTabSelectionChanged(mTabIndex, true);
}
}
/**
* Let {@link TabHost} know that the user clicked on a tab indicator.
*/
static interface OnTabSelectionChanged
{
/**
* Informs the TabHost which tab was selected. It also indicates if the
* tab was clicked/pressed or just focused into.
*
* @param tabIndex index of the tab that was selected
* @param clicked whether the selection changed due to a touch/click or
* due to focus entering the tab through navigation. Pass
* true if it was due to a press/click and false otherwise.
*/
void onTabSelectionChanged(int tabIndex, boolean clicked);
}
}
tab xml
<?xml version="1.0" encoding="utf-8"?> <com.sleightdemos.widget.MyTabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:footerDividersEnabled="true" android:headerDividersEnabled="true" android:textSize="@dimen/title" android:gravity="center" android:background="@drawable/titlebar" android:textColor="@color/white" /> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.sleightdemos.widget.MyTabWidget android:id="@+id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingTop="31dip" /> <FrameLayout android:id="@+id/tabcontent" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" /> </LinearLayout> </com.sleightdemos.widget.MyTabHost>
tab_content xml
<?xml version="1.0" encoding="utf-8"?> <com.sleightdemos.widget.MyTabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.sleightdemos.widget.MyTabWidget android:id="@+id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@+id/tabcontent" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" /> </LinearLayout> </com.sleightdemos.widget.MyTabHost>
tab_indicator xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dip" android:layout_height="64dip" android:layout_weight="1" android:orientation="vertical"> <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:textColor="@color/white" android:singleLine="true" android:ellipsize="marquee" /> </RelativeLayout>
tab_inicator_child xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dip" android:layout_height="64dip" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:textColor="@color/white" android:singleLine="true" android:ellipsize="marquee" android:text="" /> </RelativeLayout>
values/dimens.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="title">20sp</dimen> </resources>