看到這個題目,我想做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).
就寫到這裡,網上例子也很多,你們可以自行尋找.這裡只是簡單說明下原理.