使用 Android ActionBarCompat 製作導覽列(3)

ActionBar Tab

接續:使用 Android ActionBarCompat 製作導覽列(2)

Fragment 的參數傳遞

前面的例子是 Activity 加入 Fragment。接下來要做 Fragment 切換到另一個 Fragment,並且說明如何傳遞參數。

DetailFragment.java

DetailFragment 和 MainFragment 基本上一樣,只是多了接參數的部份:
public static final String DETAIL_VALUE = "detail_value";
private String value = "";

private MainActivity activity;

public static DetailFragment create(Bundle bdl){
    DetailFragment detailFragment = new DetailFragment();
    detailFragment.setArguments(bdl);
    return detailFragment;
}
傳遞參數使用 setArguments(bdl),Bundle 則是儲存要傳遞的值。
接收則是:
private void getArgumentsValue(){
    value = this.getArguments().getString(DETAIL_VALUE);
}
然後記得讓 ActionBar 顯示 back 箭號:
private void initActionBar() {
    ActionBar actionBar = activity.getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setHomeButtonEnabled(true);
}
因為是在 Fragment,所以必須從 Activity 中去取得 ActionBar,對其做設定,如果要設定標題,也可以在這裡做。這些都寫在 Fragment 的 onCreate() 裡面:
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    activity = (MainActivity) this.getActivity();       
    getArgumentsValue();
    initActionBar();
}

MainFragment.java

然後回到 MainFragment,因為要由它切換到 DetailFragment,而它有一個按鈕
Button btnOpenDetail = (Button) view.findViewById(R.id.btnOpenDetail);
btnOpenDetail.setOnClickListener(onClickOpenDetail);
這兩行在 initView 中,接著處理按鈕事件來切換到 DetailFragment:
private OnClickListener onClickOpenDetail = new OnClickListener() {

    @Override
    public void onClick(View v) {
        FragmentManager fragmentManager = activity.getSupportFragmentManager();
        Bundle bdl = new Bundle();
        bdl.putString(DetailFragment.DETAIL_VALUE, "ABC-123-(*.*)y");

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.content_frame, DetailFragment.create(bdl));
        fragmentTransaction.addToBackStack("detail");
        fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        fragmentTransaction.commit();
    }
};
這裡透過 FragmentManager 及 FragmentTransaction 來切換到另一個 Fragment ,並且透過 Bundle 來儲存要傳遞的資料,這樣就完成了切換。

使用 Tab

Tab 只能用在 Activity,因為每個 tab 都是一個 Fragment,而 Activity 包含 Fragment。所以建立一個簡單的 TabActivity 繼承 ActionBarActivity,然後在 onCreate 中加入我們的 initActionBar():
private void initActionBar() {
    ActionBar actionBar = this.getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setDisplayShowHomeEnabled(true);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setIcon(R.drawable.ic_launcher);
    actionBar.setTitle("ActionBarCompat Demo");

    //create Actionbar Tabs
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    //first tab
    tab = actionBar.newTab().setTabListener(new AFragment());
    tab.setText("TAB A");
    actionBar.addTab(tab);

    //second tab
    tab = actionBar.newTab().setTabListener(new BFragment());
    tab.setText("TAB B");
    actionBar.addTab(tab);
}
重點在於 setNavigationMode 指定為 NAVIGATION_MODE_TABS,接著就是加入 tab。tab fragment 和之前的 fragment 差不多,但要實作 TabListener。

AFragment.java

public class AFragment extends Fragment implements TabListener {

    private Fragment mFragment;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_a, container, false);
        return view;
    }

    @Override
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) {

    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        mFragment = new AFragment();
        ft.add(android.R.id.content, mFragment);
        ft.attach(mFragment);
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if (mFragment != null) {
            ft.remove(mFragment);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mFragment != null) {
            mFragment = null;
        }
    }
}
唯一的差別是,之前的 fragment 是由自製的 create() 靜態方法來產生,這裡則是在 onTabSelected (選到該tab) 中產生,而在 onTabUnselected (選到其他tab) 後移除。

後記

如果專案是一開始就使用 ActionBar,並且沒有向下相容要處理的話,製作上應該會簡單些,我從 Activity 轉換成 Fragment 時,專案整個混亂到不行,改得頭超痛的,大多是邊實驗邊修改,所以還有滿多 ActionBar 的功能沒做到,可能要等未來有用到時才會去接觸吧,趁著還有印象,抓空檔趕快記下來,原本以為是一篇文章,結果越寫越多,竟然能拆成三篇,累~~

範例程式碼:https://github.com/tony915/ActionBarCompatDemo

參考資料:

本文網址:https://blog.tonycube.com/2014/02/android-actionbarcompat-3.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

6 則留言

  1. 請問...我從github下載您的專案,可是卻無法匯入= =
    他找不到專案檔....
    我用土法煉鋼的方式一一複製寫入,執行後發現button tab有問題....會閃退
    detail fragment在螢幕轉換的時候會閃退.....

    回覆刪除
    回覆
    1. 我已經重新 push 新的版本到 github,把專案檔加入了,可以重新下載。

      刪除
  2. 請教版主
    我在menu 的 showAsAction
    使用ifRoom 還是always
    我的手機 就算倒立
    還是看不到 icon 或是 文字

    回覆刪除
    回覆
    1. 不確定是什麼原因,如果你是較舊的手機,手機上有 menu 鍵的,按一下,應該會從下面往上跑出選單。

      刪除
    2. 是的 , 我在menu鍵可以找的到
      但我的手機是samsung s3 這樣手機會太舊嗎?
      還有沒有辦法讓它顯示出來?

      刪除
    3. s3沒用過不知道,較舊的手機是指有四個實體按鍵的,s3 好像只有 3 個。
      沒有錯誤訊息不知道怎麼解,看看整個過程中有沒有漏掉什麼步驟吧。

      刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。