Android"第五大組件"之Fragment

一、簡介


Fragment
Fragment

Android 在 Android 3.0(API 級別 11)中引入了Fragment,主要是為了給大屏幕(如平板電腦)上更加動態(tài)和靈活的 UI 設(shè)計提供支持察绷。

Fragment 表示 Activity 中的行為或用戶界面部分。您可以將多個Fragment組合在一個 Activity 中來構(gòu)建多窗格 UI,以及在多個 Activity 中重復(fù)使用某個Fragment休傍。您可以將Fragment視為 Activity 的模塊化組成部分,它具有自己的生命周期蹲姐,能接收自己的輸入事件磨取,并且您可以在 Activity 運行時添加或移除Fragment(有點像您可以在不同 Activity 中重復(fù)使用的“子 Activity”)。

Fragment必須始終嵌入在 Activity 中柴墩,其生命周期直接受宿主 Activity 生命周期的影響忙厌。

您可以通過在 Activity 的布局文件中聲明片段,將其作為 <fragment> 元素插入您的 Activity 布局中江咳,或者通過將其添加到某個現(xiàn)有 ViewGroup逢净,利用應(yīng)用代碼進(jìn)行插入

因為Fragment的使用頻率僅次于Activity歼指,有的項目中Fragment使用頻率比Activity還要高爹土,并且它有自己的生命周期,所以踩身,我稱它為“Android第五大組件”

二胀茵、使用


1. 創(chuàng)建Fragment

/**
 * 創(chuàng)建Fragment
 */
public class RightFragment extends Fragment {

    public static final String TAG = "RightFragment";

    /**
     * 生命周期方法:與Activity建立關(guān)聯(lián)時調(diào)用
     */
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.d(TAG, "onAttach");
    }

    /**
     * 生命周期方法:初始化創(chuàng)建時回調(diào)
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
    }

    /**
     * 生命周期方法:為Fragment創(chuàng)建視圖時調(diào)用
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView");
        // 加載視圖文件
        View view = inflater.inflate(R.layout.right_fragment, container, false);
        return view;
    }

    /**
     * 生命周期方法:在確保Activity創(chuàng)建完成并且Fragment的視圖結(jié)構(gòu)創(chuàng)建完成后調(diào)用
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "onActivityCreated");
    }

    /**
     * 生命周期方法:與Activity類似,對用戶可見時挟阻,在Activity的onStart之后回調(diào)
     */
    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    /**
     * 生命周期方法:與Activity類似琼娘,用戶可見且可交互時,在Activity的onResume之后回調(diào)
     */
    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
    }

    /**
     * 生命周期方法:與Activity類似附鸽,Activity被遮擋可見不可交互時脱拼,在Activity的onPause之后回調(diào)
     */
    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
    }

    /**
     * 生命周期方法:與Activity類似,Activity被其他非dialog Activity覆蓋不可見時坷备,在Activity的onStop之后回調(diào)
     */
    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "onStop");
    }

    /**
     * 生命周期方法:Activity回調(diào)onDestroy之后熄浓,銷毀Fragment的視圖時調(diào)用
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG, "onDestroyView");
    }

    /**
     * 生命周期方法:在onDestroyView之后,不再使用Fragment省撑,銷毀Fragment實例時調(diào)用
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    /**
     * 生命周期方法:與Activity解除關(guān)聯(lián)時調(diào)用
     */
    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "onDetach");
    }

}

2. 編寫xml布局

right_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="#00ff00"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textSize="20sp"
        android:text="This is right fragment"
        />

</LinearLayout>

3. 使用Fragment

  • 靜態(tài)引用

MainActivity中引用:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- 引用全類名 -->
    <fragment
        android:name="com.example.fragmenttest.RightFragment"
        android:id="@+id/left_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
  • 動態(tài)引用
    activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/right_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

</FrameLayout>
// MainActivity中代碼引用
// 獲取fm
FragmentManager fragmentManager = getSupportFragmentManager();
// 開啟事務(wù)
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 指定容器添加Fragment
transaction.add(R.id.right_layout, fragment);
// 提交事務(wù)
transaction.commit();

三玉组、Fragment生命周期


Fragment生命周期
Fragment生命周期

Activity與Fragment的生命周期交替:

四谎柄、FragmentManager


顧名思義,F(xiàn)ragmentManager惯雳,是管理Fragment的一個類

  • 分類:

    • android.app.FragmentManager
      在3.0以上版本使用朝巫,通過getFragmentManager()獲取

    • android.support.v4.app.FragmentManager
      兼容版本,可以讓Fragment在Android各個版本功能保持一致石景,比如Fragment嵌套Fragment就是在Android4.2才支持的劈猿,如果用上面的FragmentManager就會崩潰。
      必須在FragmentActivity的子類中才能使用潮孽,通過getSupportFragmentManager()獲取

  • 常用操作:

    • findFragmentById()(對于在 Activity 布局中提供 UI 的片段)或 findFragmentByTag()(對于提供或不提供 UI 的片段)獲取 Activity 中存在的片段揪荣。
    • popBackStack()(模擬用戶發(fā)出的返回命令)將片段從返回棧中彈出。
    • addOnBackStackChangedListener() 注冊一個偵聽返回棧變化的偵聽器往史。
    • beginTransaction() 打開一個 FragmentTransaction仗颈,通過它來執(zhí)行某些事務(wù),如添加和移除片段椎例。

五挨决、FragmentTransaction


FragmentTransaction可以對Fragment執(zhí)行添加、移除订歪、替換以及其他操作脖祈。 您提交給 Activity 的每組更改都稱為事務(wù)。

// 通過FragmentManager開啟事務(wù)
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

常用操作:

  • add() 添加
  • remove()移除
  • hide()隱藏
  • show()展示
  • replace()替換
  • commit()提交 刷晋,一個FragmentTransaction只能提交一次盖高,最后提交
  • addToBackStack(null)添加到回退棧,用戶通過按返回按鈕返回上一個Fragment眼虱。
  • 向 FragmentTransaction 添加更改的順序無關(guān)緊要喻奥,不過:
    • 您必須最后調(diào)用 commit()
    • 如果您要向同一容器添加多個片段,則您添加片段的順序?qū)Q定它們在視圖層次結(jié)構(gòu)中的出現(xiàn)順序
  • 調(diào)用 commit() 不會立即執(zhí)行事務(wù)捏悬,而是在 Activity 的 UI 線程(“主”線程)可以執(zhí)行該操作時再安排其在線程上運行撞蚕。不過,如有必要邮破,您也可以從 UI 線程調(diào)用 executePendingTransactions() 以立即執(zhí)行 commit() 提交的事務(wù)诈豌。通常不必這樣做仆救,除非其他線程中的作業(yè)依賴該事務(wù)抒和。

六、Fragment通信


1. Fragment和Activity通信

片段可以通過 getActivity() 訪問 Activity 實例彤蔽,并輕松地執(zhí)行在 Activity 布局中查找視圖摧莽、調(diào)用其中的方法等任務(wù)。

View listView = getActivity().findViewById(R.id.list);

同樣地顿痪,您的 Activity 也可以使用 findFragmentById()findFragmentByTag()镊辕,通過從 FragmentManager 獲取對 Fragment 的引用來調(diào)用片段中的方法油够。例如:

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

2. Fragment之間通信

實際和上面差不多,一個Fragment獲取相關(guān)的Activity征懈,然后由Activity再獲取另一個Fragment石咬,從而實現(xiàn)這兩個Fragment之間的通信

3. Fragment傳值

通過setArguments()給Fragment傳遞值

RightFragment fragment = new RightFragment();
// bundle,鍵值對映射
Bundle bundle = new Bundle();
bundle.putString("test","傳遞的值");
fragment.setArguments(bundle);

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.right_layout, fragment);
transaction.addToBackStack(null);
transaction.commit();

通過getArguments()獲取值

public class RightFragment extends Fragment {

    public static final String TAG = "RightFragment";
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 獲取bundle
        Bundle bundle = getArguments();
        if(bundle != null){
            String test = bundle.getString("test");
            Log.e(TAG,test); // 將會輸出“傳遞的值”
        }

    }

3. Fragment通過startActivityForResult()獲取回傳值

如果我們在Fragment中跳轉(zhuǎn)Activity想要獲取回傳值卖哎,我們可以通過Fragment.startActivityForResult()來實現(xiàn)鬼悠,切記,是調(diào)用Fragment的該方法亏娜,而不是Activity的焕窝,否則onActivityResult()回調(diào)將會在Fragment所在的Activity中被回調(diào)。

不貼代碼了维贺,和Activity的基本一致它掂,在Fragment中通過startActivityForResult()打開Activity,在Activity中通過setResult()回傳值溯泣,在Fragment中通過重寫onActivityResult()獲取值虐秋。

七、Fragment轉(zhuǎn)場動畫


1. 自帶動畫效果

使用FragmentTransaction.setTransition()設(shè)置发乔,設(shè)置后熟妓,添加和移除時就會有動畫效果;在操作Fragment之前調(diào)用才有效

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 1. FragmentTransaction.TRANSIT_NONE:無動畫栏尚,默認(rèn)
// 2. FragmentTransaction.TRANSIT_FRAGMENT_OPEN:打開樣式動畫效果
// 3. FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:關(guān)閉樣式動畫效果
// 4. FragmentTransaction.TRANSIT_FRAGMENT_FADE:淡入淡出動畫效果
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);

transaction.add(R.id.right_layout, fragment);
transaction.addToBackStack(null);
transaction.commit();

2. 自定義動畫

使用FragmentTransaction.setCustomAnimations()設(shè)置起愈,需要在操作Fragment之前調(diào)用

  • android.app.Fragment
android.app.FragmentTransaction
public abstract FragmentTransaction setCustomAnimations(@AnimatorRes int var1,@AnimatorRes int var2,@AnimatorRes int var3,@AnimatorRes int var4)

由上面的文檔可看出,使用該Fragment译仗,需要使用屬性動畫抬虽,在res下新建animator文件夾,res/animator,在其中創(chuàng)建以<set>纵菌、<objectAnimator>阐污、<valueAnimator>為根布局的動畫文件

  • android.support.v4.app.Fragment
android.support.v4.app.FragmentTransaction
public abstract FragmentTransaction setCustomAnimations(@AnimRes int enter,@AnimRes int exit,@AnimRes int popEnter,@AnimRes int popExit)

由上面的文檔可看出,使用該Fragment咱圆,需要使用補間動畫笛辟,在res下新建anim文件夾,res/anim,在其中創(chuàng)建以<set>序苏、<rotate>手幢、<scale>等幾個補間動畫的標(biāo)簽為根布局的動畫文件

八、Fragment結(jié)合Viewpager使用


關(guān)于Fragment結(jié)合Viewpager使用忱详,可以看我的ViewPager 全面總結(jié)

最后推薦三篇Fragment好文:
Fragment全解析系列(一):那些年踩過的坑
Fragment全解析系列(二):正確的使用姿勢
Fragment之我的解決方案:Fragmentation


個人總結(jié)围来,水平有限,如果有錯誤,希望大家能給留言指正监透!如果對您有所幫助桶错,可以幫忙點個贊!如果轉(zhuǎn)載胀蛮,希望可以留言告知并在顯著位置保留草帽團(tuán)長的署名和標(biāo)明文章出處院刁!最后,非常感謝您的閱讀粪狼!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黎比,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸳玩,更是在濱河造成了極大的恐慌阅虫,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件不跟,死亡現(xiàn)場離奇詭異颓帝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)窝革,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門购城,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虐译,你說我怎么就攤上這事瘪板。” “怎么了漆诽?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵侮攀,是天一觀的道長。 經(jīng)常有香客問我厢拭,道長兰英,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任供鸠,我火速辦了婚禮畦贸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘楞捂。我一直安慰自己薄坏,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布寨闹。 她就那樣靜靜地躺著胶坠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鼻忠。 梳的紋絲不亂的頭發(fā)上涵但,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機(jī)與錄音帖蔓,去河邊找鬼矮瘟。 笑死,一個胖子當(dāng)著我的面吹牛塑娇,可吹牛的內(nèi)容都是我干的澈侠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼埋酬,長吁一口氣:“原來是場噩夢啊……” “哼哨啃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起写妥,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拳球,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后珍特,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祝峻,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年扎筒,在試婚紗的時候發(fā)現(xiàn)自己被綠了莱找。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡嗜桌,死狀恐怖奥溺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情骨宠,我是刑警寧澤浮定,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站层亿,受9級特大地震影響壶唤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棕所,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一闸盔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧琳省,春花似錦迎吵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至桦他,卻和暖如春蔫巩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工圆仔, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留垃瞧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓坪郭,卻偏偏與公主長得像个从,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子歪沃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容