一、簡介

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生命周期

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)明文章出處院刁!最后,非常感謝您的閱讀粪狼!