看到这个题目,我想做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).
就写到这里,网上例子也很多,你们可以自行查找.这里只是简单说明下原理.