文章目錄
- 為什么要使用碎片(Fragment)
- 實例
- 布局文件
- Fragment
- Activity
- 動態添加碎片
- 布局文件
- Fragment
- Activity
- 碎片通信
- Fragment
- 布局文件
- Activity
- 生命周期
為什么要使用碎片(Fragment)
我們在手機上看新聞可能是這樣的:
- RecyclerView 顯示了一組新聞標題
- 點擊一個新聞后會跳轉到新界面顯示詳細內容
但當設備屏幕很大時,我們完全可以將 RecyclerView 和 詳細內容 分別放在兩個 碎片 中,然后引入同一個 活動:
Fragment 的定義為小活動,同樣具有生命周期,但比一個 Activity 更細化的管理空間。
實例
布局文件
定義兩個布局文件:
left_fragment.xml
:
<LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="Button"/></LinearLayout>
right_fragment.xml
:
<LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:background="#00ff00"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><TextViewandroid:id="@+id/tx1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:textSize="20sp"android:text="This is right fragment"/></LinearLayout>
fragment_layout.xml
:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/left_fragment"android:name="com.example.activitytest.Fragment.LeftFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/><fragmentandroid:id="@+id/right_fragment"android:name="com.example.activitytest.Fragment.RightFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/>
</LinearLayout>
Fragment
LeftFragment.java
:
public class LeftFragment extends Fragment {@Override// 重寫Fragment中onCreateView方法public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.left_fragment, container, false);}
}
RightFragment.java
:
public class RightFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.right_fragment, container, false);}
}
Activity
FragmentActivity.java
:
public class FragmentActivity extends AppCompatActivity {protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.fragment_layout);}
}
運行結果:
動態添加碎片
Fragment 碎片的真正強大的地方在于可以在程序運行過程中動態地添加到活動中,下面將做一個點擊按鈕切換右邊碎片的案例:
布局文件
rightfrag_two.xml
:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:background="#ffff00"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/tx2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:textSize="20sp"android:text="This is another right fragment"/>
</LinearLayout>
修改 fragment_layout.xml
,將右側碎片替換成一個 FrameLayout 布局:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/left_fragment"android:name="com.example.activitytest.Fragment.LeftFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/><!--<fragmentandroid:id="@+id/right_fragment"android:name="com.example.activitytest.Fragment.RightFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/>--><FrameLayoutandroid:id="@+id/right_layout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/>
</LinearLayout>
Fragment
public class RightFragTwo extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.rightfrag_two, container, false);}
}
Activity
修改 FragmentActivity.java
,實現通過點擊 左側 Button 按鈕來動態替換 RightFragment 和 RightFragTwo 兩個碎片:
public class FragmentActivity extends AppCompatActivity implements View.OnClickListener {int type = 1; // 輔助判斷當前right_layout的布局是RightFragment還是RightFragTwoprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.fragment_layout);Button button1 = findViewById(R.id.button_1); // fragment_layout.xml中replaceFragment(new RightFragment());button1.setOnClickListener(this);}private void replaceFragment(Fragment fragment){// 獲取碎片管理器FragmentManager supportFragmentManager = getSupportFragmentManager();// 獲取事務,beginTransaction開啟一個事務FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();// 提供 容器id 和 待添加的碎片實例,實現像容器內動態替換碎片fragmentTransaction.replace(R.id.right_layout, fragment);// 提交事務fragmentTransaction.commit();}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.button_1:if(type == 1){replaceFragment(new RightFragTwo());type = 2;}else{replaceFragment(new RightFragment());type = 1;}break;}}
}
此時雖然實現了動態替換,但是會發現直接點擊 Back 會退出程序,可以使用 fragmentTransaction.replace(R.id.right_fragment, fragment);
方法,它可以接受一個名字用于描述返回棧的狀態,一般傳入 null
即可:
碎片通信
碎片通信又可細分為 碎片和活動之間進行通信、碎片和碎片之間通信。這里實現前者的一個實例:
Fragment
修改一下 RightFragment.java
,在其中添加一個 TextView 成員,用于在其它類中管理 TextView 的內容:
public class RightFragment extends Fragment {public TextView textView;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentView view = inflater.inflate(R.layout.right_fragment, container, false);textView = view.findViewById(R.id.tx1);return view;}
}
布局文件
在 left_fragment.xml
中再添加一個 button_2:
<Buttonandroid:id="@+id/button_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="send"/>
其作用是更改 RightFragment.java
中 TextView 的內容。為了實現這一功能,我們需要修改 FragmentActivity.java
文件:
Activity
創建 button_2
的實例 button2
,并設置監聽事件:
在 onClick
方法中完善點擊 button2
之后的操作:
- 通過
findFragmentById
方法獲取并創建相應碎片的實例 - 通過設置該實例更改 TextView 控件的內容
運行結果:
生命周期
碎片的生命周期內有四種狀態:
- 運行狀態: 當一個碎片是可見的,并且所關聯的活動也是正在處于運行狀態的時候,該碎片處于運行狀態。
- 暫停狀態: 當一個活動處于暫停狀態時(另一個未占滿屏幕的活動處于棧頂),與它相關聯的可見碎片也處于暫停狀態。
- 停止狀態: 當一個活動處于停止狀態時,與它相關聯的碎片也會進入到停止狀態,或者調用了 FragmentTransaction 的
remove()
、replace()
方法將碎片從活動中移除,并且在事務提交之前調用addToBackStack()
方法,這時碎片也會進入到停止狀態。進入到停止狀態的碎片對用戶來說是完全不可見的,也有可能會被系統回收。 - 銷毀狀態: 當活動被銷毀時,與它相關聯的碎片也會進入到銷毀狀態,或者調用了 FragmentTransaction 的
remove()
、replace()
方法將碎片從活動中移除,并且在事務提交之前沒有調用addToBackStack()
方法,碎片也會進入到銷毀狀態。
活動中有的回調方法碎片中幾乎都有,且提供了一些附加的回調方法:
- onAttach(): 當碎片和活動建立關聯的時候調用
- onCreateView(): 為碎片創建視圖(加載布局)時調用
- onActivityCreated(): 確保與碎片相關聯的活動一定已經創建完畢的時候調用
- onDestroyView(): 當與碎片關聯的視圖被移除的時候調用
- onDetach(): 當碎片和活動解除關聯的時候調用