如何使用Fragment建立TabActivity之一

Fragment是3.0以後才出現的類別庫, 因此要下載官方的support library.


如果要下載官方的Support library, 你要先打開eclipse->window->Android SDK Manager
接著你就會看到以下畫面-> 選擇Extra的Android Support下載





然後在你的android sdk資料夾之下,看到多出一個extras的資料夾, 以我的資料夾為例子 \android-sdk-windows\extras\android\support\v4\android-support-v4.jar, 這個就是我們所需要的support library.



當我們建立一個專案的時候, 只要在專案下面在建立一個lib, 然後把android-support-v4.jar加進去,
接著點選專案右鍵, 選擇properties->Libraries->Add Library 將lib資料夾內的android-support-v4.jar加進去。

記得要到Order and Export那邊將android-support-v4.jar打勾。


如此一來就可以使用這個library的所有類別了。
官方說明如下
我們可以看到這個類別庫大致上有以下這幾類

Fragment
FragmentManager
FragmentTransaction
ListFragment
DialogFragment
LoaderManager
Loader
AsyncTaskLoader
CursorLoader

另外這邊有一個重點就是, 為了讓之前Android版本能夠跑我們的程式,
可以在AndroidManifest.xml上面進行設定。
<uses-sdk android:minSdkVersion="4" />

這樣一來, 無論手機上的android版本多舊, 我們仍然可以跑我們要的程式。
接下來進入我們的重點了, 如何使用TabActivity,
其實在我們下載android-support-v4.jar裡面, 就已經存在很多範例了,
但是為了簡化他的範例, 因此我用官網所提供的範例進行簡化。


首先新增一個fragment_tabs.xml
                
                
<TabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
t" android:layout_height="match_par
android:layout_width="match_pare nent"> <LinearLayout android:orientation="vertical"
t_height="match_parent"> <FrameLay
android:layout_width="match_parent" android:layo uout android:id="@android:id/tabcontent" android:layout_width="0dp"
ameLayout android:id="@+and
android:layout_height="0dp" android:layout_weight="0"/> <F rroid:id/realtabcontent" android:layout_width="match_parent" android:layout_height="0dp"
ight="wrap_content" android
android:layout_weight="1"/> <HorizontalScrollView android:layout_h e:layout_width="fill_parent" android:scrollbars="none" android:id="@+id/scroller"> <TabWidget
nt" android:layout_height="wr
android:id="@android:id/tabs" android:orientation="horizontal" android:layout_width="match_par eap_content" android:layout_weight="0"/> </HorizontalScrollView> </LinearLayout>
</TabHost>

這邊我們建立一個TabHost的元件, 然後我想讓TabWidget能夠呈現在下方,
因此用LinearLayout包起來,
讓上方為一個FrameLayout(橙色部分), 下方才是我們的TabWidget(藍色部分)。

首先要建立一個FragmentActivity的子類別,
                
                
public class FragmentTabs extends FragmentActivity{
    @Override
void onCreate(Bundle savedInstanceState) {         super
    protected  .onCreate(savedInstanceState);     }
}

基本上跟一般的Activity沒什麼不一樣, 也是先建立一個onCreate的方法。

接著我們就把TabWidget元件從xml取出, 並且初始化。

                
                
public class FragmentTabs extends FragmentActivity{
    private TabHost mTabHost;     @Override
anceState) {         super.onCreate(savedInstanceState);
    protected void onCreate(Bundle savedIns t         setContentView(R.layout.fragment_tabs);
.id.tabhost);         mTabHost.setup();     } }
        mTabHost = (TabHost)findViewById(android.
R

在這邊要注意一下, 在之前我們的類別是繼承TabActivity,
因此我們常常只需要getTabHost(); 就可以取得TabHost的物件了,
原因出在我們的TabActivity裡面就對TabHost元件初始化了,
但是現在是從xml取出物件, 因此要多加上setup()這個方法,
才能夠進行add的動作。

官網說法
Call setup() before adding tabs if loading TabHost using findViewById(). However: You do not need to call setup() after getTabHost() in TabActivity. 

可以參考看看

接著我們必須宣告一個TabManager來處理當切換分頁的時候, 必須進行的一些動作。
類別長這樣:

                
                
public class TabManager implements TabHost.OnTabChangeListener {
    private final FragmentActivity mActivity;
e final int mContainerId;     priva
    private final TabHost mTabHost;     priva tte final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>();
al String tag;       
    TabInfo mLastTab;     static final class TabInfo {         private fi n  private final Class<?> clss;         private final Bundle args;
ass<?> _class, Bundle _args) {    
        private Fragment fragment;         TabInfo(String _tag, C l         tag = _tag;             clss = _class;             args = _args;         }     }
l Context mContext;         public DummyTabFactory(Context context) {
    static class DummyTabFactory implements TabHost.TabContentFactory {         private fin a            mContext = context;         }         @Override         public View createTabContent(String tag) {             View v = new View(mContext);
y, TabHost tabHost, int container
            v.setMinimumWidth(0);             v.setMinimumHeight(0);             return v;         }     }     public TabManager(FragmentActivity activi tId) {         mActivity = activity;         mTabHost = tabHost;         mContainerId = containerId;         mTabHost.setOnTabChangedListener(this);     }
 = tabSpec.getTag();         TabInfo info = new TabInfo(tag, clss, args);  
    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {         tabSpec.setContent(new DummyTabFactory(mActivity));         String ta g       info.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);         if (info.fragment != null && !info.fragment.isDetached()) {
();         }         mTabs.put(tag, info);         mTabHost.addTab(tabSpec);     }     @Ove
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();             ft.detach(info.fragment);             ft.commi trride     public void onTabChanged(String tabId) {      TabInfo newTab = mTabs.get(tabId);         if (mLastTab != newTab) {             FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
ab.fragment = Fragment.instantiate(
            if (mLastTab != null) {                 if (mLastTab.fragment != null) {                     ft.detach(mLastTab.fragment);                 }             }             if (newTab != null) {                 new TmActivity,                         newTab.clss.getName(), newTab.args);                 ft.add(mContainerId, newTab.fragment, newTab.tag);                 if (newTab.fragment == null) {                     ft.detach(mLastTab.fragment);
   }                    
                } else {                     mActivity.getSupportFragmentManager().popBackStack();                     ft.replace(mContainerId, newTab.fragment);                     ft.attach(newTab.fragment);                 }                 mLastTab = newTab;             ft.commit();             mActivity.getSupportFragmentManager().executePendingTransactions();         }          }
}


超複雜嗎? 你也可以不用管這個類別直接拿過用即可, 新建一個TabManager.java, 然後把上面內容複製貼上就可以直接使用了!

那麼以下內容你可以直接跳過
********************                      跳過                ******************************

基本上是照著官網上所寫的來進行,

你會發現在這個類別當中, 存在兩個靜態類別, 分別是TabInfo以及DummyTabFactory。

                
                
static final class TabInfo {
    private final String tag;
    private final Class<?> clss;
    private final Bundle args;
    TabInfo(String _tag, Clas
    private Fragment fragment; s<?> _class, Bundle _args) {
rgs;     } }
        tag = _tag;         clss = _class;         args = _
a
TabInfo就是每一個分頁當中存在的資訊, 例如該分頁的名稱、傳到哪一個類別以及傳過去的時候, 所帶的Bundle。

                
                
static class DummyTabFactory implements TabHost.TabContentFactory {
    private final Context mContext;
ontext) {         mContext = context;     }
    public DummyTabFactory(Context  c    @Override     public View createTabContent(String tag) {
(0);         v.setMinimumHeight(0);
        View v = new View(mContext);         v.setMinimumWidt h        return v;     }
}
DummyTabFactory目的是用來創造一個分頁所形成的View, 當你按下任一分頁, 它就會根據對應的View來進行切換。

                
                
public TabManager(FragmentActivity activity, TabHost tabHost, int containerId) {
    mActivity = activity;     mTabHost = tabHost;
TabChangedListener(this); }
    mContainerId = containerId;     mTabHost.setO
n
一開始從建構子傳入的就是該FragmentActivity, 再來就是TabHost物件, 最後是一個容器的id,
這個容器就是用來裝我們切換分頁的view, 還記得fragment_tabs.xml當中, 我們用了兩個FrameLayout嗎? 這個就是放在上面的那個, 你可以對照一下後面我們會傳入的id, 就可以清楚的明白這個layout的功用。

                
                
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
    tabSpec.setContent(new DummyTabFactory(mActivity));
ew TabInfo(tag, clss, args);     
    String tag = tabSpec.getTag();     TabInfo info =  ninfo.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);
tTransaction ft = mActivity.getSupportFragmentManager().beginTr
    if (info.fragment != null && !info.fragment.isDetached()) {         Fragme nansaction();         ft.detach(info.fragment);         ft.commit();     }     mTabs.put(tag, info);     mTabHost.addTab(tabSpec);
}
這邊就是要新增一個分頁, 就必須傳入TabHost.TabSpec物件, 以及你要轉跳的java檔案, 到時候會傳到那個Fragment, 最後是如果你有需要將此Activity的一些內容(如String, int..等等)的資料傳到指定的分頁, 就可以在最後一個參數利用Bundle物件夾帶, 如果沒有, 則可以指定null。

那麼一開始他就將TabSpec的物件帶入new出來的DummyTabFactory, 方便這個分頁的內容呈現一個View。
接著又把傳入的參數丟進去TabInfo物件, 完成初始化。
當我們要進行切換fragment的時候, 就會利用FragmentTransaction的物件來進行調度,而當commit出去的時候, 就可以進行變更。
當我們進行detach動作的時候, 就表示指定該fragment會出現在某一個View當中。
當我們進行detach動作的時候, 就表示指定該fragment會從該View當中分離。 
當我們進行replace動作的時候, 才是表示將某一個fragment轉換成另外一個fragment。


官網寫法
                
                
@Override
public void onTabChanged(String tabId) {
    TabInfo newTab = mTabs.get(tabId);
ragmentTransaction ft = mActi
    if (mLastTab != newTab) {          Fvity.getSupportFragmentManager().beginTransaction();
b.fragment != null) {          
        if (mLastTab != null) {            if (mLastT a     ft.detach(mLastTab.fragment);            }         }
nt == null) {                
        if (newTab != null) {             if (newTab.fragm e newTab.fragment = Fragment.instantiate(mActivity,
gs);                 ft.add(mContainerId, newTab.fragmen
                    newTab.clss.getName(), newTab.a rt, newTab.tag);             } else {                 ft.attach(newTab.fragment);             }         }
gTransactions();     } }
        mLastTab = newTab;         ft.commit();         mActivity.getSupportFragmentManager().executePendi
n
一開始先判斷按下的分頁是不是前一個分頁, 如果不是, 則進行處理,
那一開始我們就會把前一個分頁內容做檢查, 看是不是空的,
如果不是空的, 則把前一個分頁從分頁管理者的內容中移除,
再來就是檢查我們新的分頁是否有內容, 如果沒有,
我們就new一個空間讓他建立新的分頁,
然後加入到分頁管理者的儲存器當中,
如果有內容, 則直接指派該分頁是我們目前要呈現的分頁,
最後確定以後, 就把新的分頁跟舊的分頁設定為同一個分頁,
接著送交, 進行更新, 接著執行分頁轉換。

但是! 官網的做法讓我產生一些問題, 因此我做了修改,
大致上如下:

                
                
@Override
public void onTabChanged(String tabId) {
    TabInfo newTab = mTabs.get(tabId);
       FragmentTransaction ft = m
        if (mLastTab != newTab) {       Activity.getSupportFragmentManager().beginTransaction();
astTab.fragment != null) {         
            if (mLastTab != null) {                 if (m L            ft.detach(mLastTab.fragment);                 }             }
.instantiate(mActivity,          
            if (newTab != null) {                 newTab.fragment = Fragmen t               newTab.clss.getName(), newTab.args);
 newTab.tag);                 if (newTab.fragment == null) {      
                ft.add(mContainerId, newTab.fragment ,               ft.detach(mLastTab.fragment);                 } else {
           ft.attach(newTab.fragment);                 }      
                    ft.replace(mContainerId, newTab.fragment);                  }                          mLastTab = newTab;             ft.commit();
        }      }
            mActivity.getSupportFragmentManager().executePendingTransactions()
;
這樣就可以成功解決我的問題。


如果這邊讓你覺得看不太懂, 沒關係, 直接Copy&Paste過去就好XD


*********************************   到這邊繼續   *******************************

接著我們在onCreate就可以使用這個類別來操作我們的TabHost物件了。
                
                
public class FragmentTabs extends FragmentActivity{
    private TabHost mTabHost;
ager;     @Override     protected v
    private TabManager mTabMa noid onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.fragment_t
        super.onCreate(savedInstanceState) ;abs);         mTabHost = (TabHost)findViewById(android.R.id.tabhost);
TabHost, R.id.realtabcont
        mTabHost.setup();         mTabManager = new TabManager(this,  ment);     }
}

這樣基本TabHost的物件就初始化完成了。

讓我們利用TabManager類別的物件來操作這個TabHost吧!
                
                
public class FragmentTabs extends FragmentActivity{
    private TabHost mTabHost;
ager;     @Override     protected v
    private TabManager mTabMa noid onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.fragment_t
        super.onCreate(savedInstanceState) ;abs);         mTabHost = (TabHost)findViewById(android.R.id.tabhost);
TabHost, R.id.realtabcont
        mTabHost.setup();         mTabManager = new TabManager(this,  ment);         mTabHost.setCurrentTab(0);//設定一開始就跳到第一個分頁         mTabManager.addTab(
ragment1.class, null);         mTabManager.addTab(             mTabHost
            mTabHost.newTabSpec("Fragment1").setIndicator("Fragment1"),              F.newTabSpec("Fragment2").setIndicator("Fragment2"),             Fragment2.class, null);         mTabManager.addTab(
TabManager.addTab(             mTabHost.newTabSpec("Fragment4").setIndi
            mTabHost.newTabSpec("Fragment3").setIndicator("Fragment3"),             Fragment3.class, null);          mcator("Fragment4"),             Fragment4.class, null);     }
}

我們加入了四個子類別, 分別是Fragment1~Fragment4,
這樣代表在切換分頁的時候, 會根據指定的分別跳置不同的Fragment。

在這邊我們必須再新增4個java檔案, 檔名當然就是Fragment1~Fragment4。
在eclipse點右鍵, 
選擇sourece->override/overload 就可以找到onCreate&onCreateView這兩個方法了!
                
                
public class Fragment1 extends Fragment {
    @Override
 onCreate(Bundle savedInstanceState) {         
    public voi
d // TODO Auto-generated method stub
super.onCreate(savedInstanceState);
    }     @Override
ateView(LayoutInflater inflater, ViewGroup container, Bundle saved
    public View onCr eInstanceState) {
// TODO Auto-generated method stub
return super.onCreateView(inflater, container, savedInstanceState);
    }
}
其他的四個類別也相同。


那麼跑看看模擬器, 就會出現這樣。

怎麼會擠在一團咧XD
沒關係, 做一下調整。

                
                
public class FragmentTabs extends FragmentActivity{
    private TabHost mTabHost;
ager;     @Override     protected v
    private TabManager mTabMa noid onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.fragment_t
        super.onCreate(savedInstanceState) ;abs);         mTabHost = (TabHost)findViewById(android.R.id.tabhost);
TabHost, R.id.realtabcont
        mTabHost.setup();         mTabManager = new TabManager(this,  ment);         mTabHost.setCurrentTab(0);         mTabManager.addTab(
,             Fragment1.class, null);         mTabManager.addTab(      
            mTabHost.newTabSpec("Fragment1").setIndicator("Fragment1" )       mTabHost.newTabSpec("Fragment2").setIndicator("Fragment2"),             Fragment2.class, null);         mTabManager.addTab(
ab(             mTabHost.newTabSpec("Fragment4").setIndicator("Fragment
            mTabHost.newTabSpec("Fragment3").setIndicator("Fragment3"),             Fragment3.class, null);         mTabManager.add T4"),             Fragment4.class, null);         DisplayMetrics dm = new DisplayMetrics();   
//先取得螢幕解析度
        getWindowManager().getDefaultDisplay().getMetrics(dm);  
       int screenWidth = dm.widthPixels;    //取得螢幕的寬
 
          
            
dget tabWidget = mTabHost.getTabWidget();    //取得tab的物件
        TabW i
       int count = tabWidget.getChildCount();    //取得tab的分頁有幾個
 
       if (count > 3) {   
             for (int i = 0; i < count; i++) {   
                tabWidget.getChildTabViewAt(i)
idth)/3); //設定每一個分頁最小的寬度
                      .setMinimumWidth((screen W
           }   
         }     }
}

一開始就先取得螢幕的解析度, 接著由於我們是x軸要加寬, 所以只要取得螢幕的寬度即可,
再來算出我們一共用了幾個分頁, 假設你只想要呈現3個分頁, 因此就把螢幕的寬度除以3個分頁, 這樣一來, 畫面就會把第4個分頁放在螢幕外面, 當你需要第4個分頁的時候, 只需要拉動某一個分頁, 就會出現其他被隱藏的分頁了。

你看是不是好多了?

只要往左拉, 第4個分頁就出現了。


可是總覺得少了那麼一點東西, 加個icon好了。

                
                
public class FragmentTabs extends FragmentActivity{
    private TabHost mTabHost;
ager;     @Override     protected v
    private TabManager mTabMa noid onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.fragment_t
        super.onCreate(savedInstanceState) ;abs);         mTabHost = (TabHost)findViewById(android.R.id.tabhost);
TabHost, R.id.realtabcont
        mTabHost.setup();         mTabManager = new TabManager(this,  ment);         mTabHost.setCurrentTab(0);         mTabManager.addTab(
            this.getResources().getDrawable(                 android.
            mTabHost.newTabSpec("Fragment1").setIndicator("Fragment1" ,R.drawable.ic_dialog_alert)),Fragment1.class, null);         mTabManager.addTab(
 this.getResources().getDrawable(                 android.R.drawable.i
            mTabHost.newTabSpec("Fragment2").setIndicator("Fragment2",             c_lock_lock)),Fragment2.class, null);         mTabManager.addTab(             mTabHost.newTabSpec("Fragment3").setIndicator("Fragment3",
.addTab(             mTabHost.newTabSpec("Fr
            this.getResources().getDrawable(                 android.R.drawable.ic_input_add)),Fragment3.class, null);         mTabManage ragment4").setIndicator("Fragment4",             this.getResources().getDrawable(                 android.R.drawable.ic_delete)),Fragment4.class, null);
        DisplayMetrics dm = new DisplayMetrics();            getWindowManager().getDefaultDisplay().getMetrics(dm);
  //先取得螢幕解析度
        int screenWidth = dm.widthPixels;    //取得螢幕的寬
           
           
idget tabWidget = mTabHost.getTabWidget();    //取得tab的物件
        Tab W
       int count = tabWidget.getChildCount();    //取得tab的分頁有幾個
 
       if (count > 3) {   
             for (int i = 0; i < count; i++) {   
                tabWidget.getChildTabViewAt(i)
idth)/3); //設定每一個分頁最小的寬度
                      .setMinimumWidth((screen W
           }   
         }     }
}
圖是我從android內建的icon找的, 你可以加入你喜歡的圖示。

看起來越來越有模樣了XD

下载: http://download.csdn.net/detail/u011127787/5758245

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值