Android學習(3)---Fragment的學習


內容概要

*  這是我的第二篇博客,但爲什麼是android學習(3)呢,因爲我的第二篇博客的代碼不在這裏,只好先來寫這一篇了。
*  今天上午把android英文文檔的Fragment部分閱讀完畢,那是相當的吃力,還好有個中文的可以對照着看,這篇主要來記錄我學習Android Fragment時所經歷的一些代碼與疑惑等;

基本概念

Fragment 表示 Activity 中的行爲或用戶界面部分。您可以將多個片段組合在一個 Activity 中來構建多窗格 UI,以及在多個 Activity 中重複使用某個片段。您可以將片段視爲 Activity 的模塊化組成部分,它具有自己的生命週期,能接收自己的輸入事件,並且您可以在 Activity 運行時添加或刪除片段(有點像您可以在不同 Activity 中重複使用的“子 Activity”)。

其原理圖,一目瞭然:

這裏寫圖片描述

按照我的理解這也是模塊化的一種多樣性的展現,就像造零件,一個零件可以作爲一個東西,這一個零件和其他零件組合到一起,又成爲一個大的零件,我這麼說好粗鄙啊,,,我隱隱中覺得這個和material design有些許的聯繫,但是又覺得相去甚遠,還需學習下material design才能再做打算;

主要知識點

(1)Fragment子類

  • DialogFragment
  • ListFragment
  • PreferenceFragment

(2)使用的基本流程

  • 添加用戶界面
public static class ExampleFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.example_fragment, container, false);
        }
    }

爲了給fragment提供一個佈局,你必須實現onCreateView()回調函數,在繪製fragment佈局時Android系統會調用它。實現這個函數時需要返回fragment所屬的根View。
注意:如果你的fragment時ListFragment的子類,默認實現從onCreateView()返回一個ListView,所以你不需要實現它。
爲了從onCreateView()返回一個佈局,你可以從layout resource定義的XML文件inflate它。爲了便於你這樣做,onCreateView()提供一個LayoutInflater對象。

inflate()函數需要以下三個參數:
要inflate的佈局的資源ID。
被inflate的佈局的父ViewGroup。傳入container很重要,這是爲了讓系統將佈局參數應用到被inflate的佈局的根view中去,由其將要嵌入的父view指定。
一個布爾值,表明在inflate期間被infalte的佈局是否應該附上ViewGroup(第二個參數)。(在這個例子中傳入的是false,因爲系統已經將被inflate的佈局插入到容器中(container)——傳入true會在最終的佈局裏創建一個多餘的ViewGroup。)

  • 將fragment添加到activity之中
    兩種方法:
    1.佈局文件聲明,主要屬性:name、id;
    2.通過編碼將fragment添加到已存在的ViewGroup中;
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
  • Fragment事務管理

    想要管理activity中的fragment,可以使用FragmentManager。可以通過在activity中調用getFragmentManager()獲得。
    使用FragmentManager 可以做如下事情,包括:
    使用findFragmentById()(用於在activity佈局中提供有界面的fragment)或者findFragmentByTag()獲取activity中存在的fragment(用於有界面或者沒有界面的fragment)。
    使用popBackStack()(模仿用戶的BACK命令)從後臺棧彈出fragment。
    使用addOnBackStackChangedListener()註冊一個監聽後臺棧變化的監聽器。

  • addToBackStack
    在調用commit()之前,爲了將事務添加到fragment事務後臺棧中,你可能會想調用addToBackStatck()。這個後臺棧由activity管理,並且允許用戶通過按BACK鍵回退到前一個fragment狀態。
    代碼示例:

 // Create new fragment and transaction
 Fragment newFragment = new ExampleFragment();
 FragmentTransaction transaction = getFragmentManager().beginTransaction();

 // Replace whatever is in the fragment_container view with this fragment,
 // and add the transaction to the back stack
 transaction.replace(R.id.fragment_container, newFragment);
 transaction.addToBackStack(null);

 // Commit the transaction
 transaction.commit();
  • 與Activity交互
    (1)fragment訪問activity:
View listView = getActivity().findViewById(R.id.list);

(2)activity訪問fragment:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

(3)fragment與activity共享事件

在一些情況下,你可能需要fragment與activity共享事件。這樣做的一個好方法是在fragment內部定義一個回調接口,並需要宿主activity實現它。當activity通過接口接收到回調時,可以在必要時與佈局中的其它fragment共享信息。

舉個例子,如果新聞應用的actvity中有兩個fragment——一個顯示文章列表(fragment A),另一個顯示一篇文章(fragment B)——然後fragment A 必須要告訴activity列表項何時被選種,這樣,activity可以通知fragment B顯示這篇文章。這種情況下,在fragment A內部聲明接口OnArticleSelectedListener:

public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

然後fragment的宿主activity實現了OnArticleSelectedListener接口,並且重寫onArticleSelected()以通知fragment B來自於fragment A的事件。爲了確保宿主activity實現了這個接口,fragment A的onAttach()回調函數(當添加fragment到activity中時系統會調用它)通過作爲參數傳入onAttach()的activity的類型轉換來實例化一個OnArticleSelectedListener實例。

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

如果activity沒有實現這個接口,那麼fragment會拋出一個ClassCaseException異常。一旦成功,mListener成員會保留一個activity的OnArticleSelectedListener實現的引用,由此fragment A可以通過調用由OnArticleSelectedListener接口定義的方法與activity共享事件。例如,如果fragment A是ListFragment的子類,每次用戶點擊列表項時,系統都會調用fragment的onListItemClick()事件,然後fragment調用onArticleSelected()來與activity共享事件。

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

傳遞給onListItemClick()的參數id是點擊的列表項行id,activity(或者其它fragment)用以從應用的ContentProvider獲取文章。

以上具體參見:android文檔-fragment

DEMO

這個demo是按照文檔的最後一個例子來的,這個例子的源碼我找了好久,就是找不到,然後在StackOverFlow上搜到了一個問題,他也找不到,哈哈哈:
android-fragment-source-code-for-fragmentlayout-java

然後下載了Level18的Sample,在裏面找到了相應的源碼,提取出來在Android Studio中復原了這個莎士比亞的戲劇閱讀小程序:
這個小程序主要是根據手機的橫豎屏來判斷Layout文件的加載,橫屏加載兩個Fragment,豎屏只加載一個,具體的見源碼吧,我還沒有完全的理解透徹,感覺官網給的代碼要嚴謹好多;
源碼如下:
百度網盤-FragmentDemo

最後上幾張圖吧,無圖無真相:
橫屏:

豎屏1:

豎屏2:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章