看到这个题目,我想做andorid开发有段时间的朋友对之在熟悉不过了,不过我之前开发Tab分栏的都是用ActivityGroup模拟实现的.其实原理上和TabHost差不多:都是用LocalActivityManager.startActivity(),获取目标的window将之转化为view,最后显示出来.
其实最合理的是TabActivity+TabHost实现分栏效果,但是我之前一直没有用过,即使用的话,也是copy之paste之,主要是自己对其具体实现不了解,因此在这里我仔细看下下TabHost的实现过程,不过这个控件有点过时了,在SDK3.0后出现了Fragment将之代替.总之算是弥补下之前开发中的过失吧.
源码分析:
首先Activity要继承自TabActivity而TabActivity是继承自ActivityGroup这才是关键所在.
而TabHost其实是继承自FrameLayout的子类.在开发中我们首先要获取当前的TabHost:getTabHost(),
下面我们跟下源码:
TabActivity:
/**
* 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 TabHost getTabHost() {
ensureTabHost();
return mTabHost;
}
private void ensureTabHost() {
if (mTabHost == null) {
this.setContentView(com.android.internal.R.layout.tab_content);
}
}
/**
* Updates the screen state (current list and other views) when the
* content changes.
*
*@see Activity#onContentChanged()
*/
@Override
public void onContentChanged() {
super.onContentChanged();
mTabHost = (TabHost) findViewById(com.android.internal.R.id.tabhost);
if (mTabHost == null) {
throw new RuntimeException(
"Your content must have a TabHost whose id attribute is " +
"'android.R.id.tabhost'");
}
mTabHost.setup(getLocalActivityManager());
}
执行过程大致流程:首先我们进行setContentView();这个时候就会回调PhoneWindow里面的setContentView()方法,然后在回调
执行TabActivity中的onContentChange方法.
总之要说的是在我们getTabHost()时候就是获取到的我们自定义xml中的TabHost控件.只是过程有点绕了而已.
TabWidget继承是LinearLayout布局.
TabSpec 类:
public class TabSpec {
private String mTag;
private IndicatorStrategy mIndicatorStrategy;
private ContentStrategy mContentStrategy;
private TabSpec(String tag) {
mTag = tag;
}
/**
* Specify a label as the tab indicator.
*/
public TabSpec setIndicator(CharSequence label) {
mIndicatorStrategy = new LabelIndicatorStrategy(label);
return this;
}
/**
* Specify a label and icon as the tab indicator.
*/
public TabSpec setIndicator(CharSequence label, Drawable icon) {
mIndicatorStrategy = new LabelAndIconIndicatorStrategy(label, icon);
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.
*/
public TabSpec setContent(int viewId) {
mContentStrategy = new ViewIdContentStrategy(viewId);
return this;
}
/**
* Specify a {@link android.widget.TabHost.TabContentFactory} to use to
* create the content of the tab.
*/
public TabSpec setContent(TabContentFactory contentFactory) {
mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);
return this;
}
/**
* Specify an intent to use to launch an activity as the tab content.
*/
public TabSpec setContent(Intent intent) {
mContentStrategy = new IntentContentStrategy(mTag, intent);
return this;
}
public 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();
}
简单说明:
TabSpec一个普通的类,mTag,mIndicatorStrategy(他是一个接口:获得指示器的View),mContentStrategy(他也是个接口,获得content部分)
我们创建了一个TabSpec。
TabHost.TabSpec tabSpec = getTabHost().newTabSpec("");//创建一个指示器
设置Tab图标部分(重载函数):
1.setIndicator(CharSequence label);//引用系统的资源文件(无图片).
2.setIndicator(CharSequence label, Drawable icon)//引用系统的资源文件(包含图片);
3.setIndicator(View view);//引用自定义的资源文件,效果自己决定.
设置内容部分(重载函数):
1.setContent(int viewId);//这个viewid指的是你在tabcontent(布局文件FramLayout)中的孩子布局id.
2.setContent(TabContentFactory contentFactory);//实现这个TabContentFactory中的createTabContent方法,及返回的视图view.
3.setContent(Intent intent);//通过LocalActivityManager加载itnent对应Activity将之转为view.
最后我们将创建好的TabHost.TabSpec--add到TabHost中.
根据传入不同的参数决定实现不同的接口.不明白的可以参看源码.
PS:上面onContentChanged这个回调函数中:mTabHost.setup(getLocalActivityManager());这句话才真正的对该控件的初始化也就是show出来.
最常用的是:setIndicator(View view)和setContent(Intent intent).
就写到这里,网上例子也很多,你们可以自行查找.这里只是简单说明下原理.