碎片:
Fragment(碎片)是一種可以嵌入在Activity中的UI片段,他能讓程序更加合理和充分地利用大屏幕的空間,因而在平板上應用的非常廣泛。
基本使用方法:
首先,需要創建碎片的佈局:
left_frag.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ffff"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="this is a left frag"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
然後,創建類繼承自Fragment類,並重寫onCreateView方法,返回我們剛纔寫好的佈局:
package com.example.fragmenttest;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class LeftFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.left_frag,container);
return view;
}
}
最後,我們在Activity佈局裏面引用碎片:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/left_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.fragmenttest.LeftFragment"
/>
<fragment
android:id="@+id/right_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.fragmenttest.RightFragment"
/>
</LinearLayout>
注意這裏的RightFragment佈局代碼基本與LeftFragment一致,不再給出。
效果圖如下:
動態添加碎片時發現的小問題:
當我嘗試動態添加的時候報瞭如下錯誤:
指定的子view已經有了父佈局,你必須先移除他的父佈局,其實我前面寫Frament類引入佈局的時候埋下了伏筆
View view=inflater.inflate(R.layout.left_frag,container);
這裏inflate函數,第三個參數表示是否將當前資源id的佈局加到第二個參數對應的父佈局上。而默認情況下,若第二個參數不爲空,第三個參數默認爲true。因此,我們爲了能夠動態添加碎片,第三個參數應當手動傳入false。
View view=inflater.inflate(R.layout.left_frag,container,false);
動態添加碎片:
在發現問題之後,我們就可以正常來寫動態添加碎片的代碼了。
首先,修改Activity佈局代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/left_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.fragmenttest.LeftFragment"
/>
<FrameLayout
android:id="@+id/fl_main"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
在處理 Fragment 時(尤其是在運行時添加 Fragment 時),需遵循的一個重要原則是,您的 Activity 佈局必須包含一個可以插入 Fragment 的容器 View。
然後,開始寫動態添加的代碼:
private void addFragment() {
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.add(R.id.fl_main,new RightFragment());
transaction.commit();
}
最後,再寫一個替換碎片的代碼:
private void replaceFragment() {
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.replace(R.id.fl_main,new AnotherFragment());
transaction.addToBackStack("mTask");
transaction.commit();
}
效果圖:
與上面直接在佈局裏面添加一樣,然後我們再來調用替換函數,得到以下結果
transaction.addToBackStack(“mTask”);這句話會將碎片添加到返回棧,這樣當我們點擊手機Back鍵會回到上一個碎片,而不是直接退出程序。
Fragment與Activity之間通信:
碎片可通過 getActivity() 訪問 FragmentActivity 實例,並輕鬆執行在 Activity 佈局中查找視圖等任務(請不要在onCreateView中執行如下語句,因爲此時Activity還未創建完成,會出現空指針異常,可以在onActivityCreated中執行):
View listView = getActivity().findViewById(R.id.list);
同樣,您的 Activity 也可使用 findFragmentById() 或 findFragmentByTag(),通過從 FragmentManager 獲取對 Fragment 的引用來調用片段中的方法。例如:
FrameLayout mFragment=getSupportFragmentManager().findFragmentById(R.id.right_frag);
碎片的生命週期:
碎片必須始終託管在 Activity 中,其生命週期直接受宿主 Activity 生命週期的影響。例如,當 Activity 暫停時,Activity 的所有片段也會暫停;當 Activity 被銷燬時,所有片段也會被銷燬。
當Activity處於運行狀態時,碎片的生命週期圖
通常,您至少應實現以下生命週期方法:
onCreate()
系統會在創建片段時調用此方法。當片段經歷暫停或停止狀態繼而恢復後,如果您希望保留此片段的基本組件,則應在您的實現中將其初始化。
onCreateView()
系統會在片段首次繪製其界面時調用此方法。如要爲您的片段繪製界面,您從此方法中返回的 View 必須是片段佈局的根視圖。如果片段未提供界面,您可以返回 null。
onPause()
系統會將此方法作爲用戶離開片段的第一個信號(但並不總是意味着此片段會被銷燬)進行調用。通常,您應在此方法內確認在當前用戶會話結束後仍然有效的任何更改(因爲用戶可能不會返回)。
碎片還有幾個額外的生命週期回調,用於處理與 Activity 的唯一交互,從而執行構建和銷燬片段界面等操作。這些額外的回調方法是:
onAttach()
在片段已與 Activity 關聯時進行調用(Activity 傳遞到此方法內)。
onCreateView()
調用它可創建與片段關聯的視圖層次結構。
onActivityCreated()
當 Activity 的 onCreate() 方法已返回時進行調用。
onDestroyView()
在移除與片段關聯的視圖層次結構時進行調用。
onDetach()
在取消片段與 Activity 的關聯時進行調用。