第一行代碼學習筆記第四章——探究碎片

知識點目錄

知識點回顧

一般手機的屏幕大小在3-6英寸之間;一般平板電腦的屏幕在7-10英寸之間。隨着屏幕大小的不同,同樣的界面在視覺效果上有較大的差異。爲了同時兼顧手機和平板視覺效果,從Android3.0開始引入了碎片的概念,它可以讓界面在平板上更好地展示。

4.1 碎片是什麼

碎片(Fragment)是一種可以嵌入在活動當中的UI片段。可以將其理解爲一種迷你型的活動。有時候我們爲了充分利用屏幕的大小,可以將多個Fragment嵌入到一個活動當中。

4.2 碎片的使用方式

4.2.1 碎片的簡單用法

1. 新建碎片佈局文件

新建左側碎片佈局left_fragment.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Button"
        android:textAllCaps="false"/>

</LinearLayout>

新建右側碎片佈局right_fragment.xml:

<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>

2. 創建Fragment類

新建的LeftFragment類需要繼承Fragment,Fragment有系統內置的android.app.Fragment和support-v4庫中的android.support.v4.app.Fragment兩種,考慮更好的兼容性,建議使用android.support.v4.app.Fragment,而build.gradle文件中的appcompat-v7會將support-v4一起引入進來,所以直接引用即可。

創建LeftFragment類:

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_fragment, container, false);
        return view;
    }
}

創建RightFragment類:

public class RightFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.right_fragment, container, false);
        return view;
    }

重寫Fragment的onCreateView方法,通過inflater()方法將上面定義的佈局加載進來。

3. 使用創建的Fragment類

修改activity_main.xml文件:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"/>

    <fragment
        android:id="@+id/right_fragment"
        android:name="com.example.fragmenttest.RightFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"/>

</LinearLayout>

使用標籤在佈局中添加碎片,通過android:name屬於來顯式指明要添加的碎片類名。

4. Fragment的簡單運行效果

4.2.2 動態添加碎片

碎片不僅可以在xml中靜態加載,還可以在程序運行時動態地添加到活動中。

新建another_right_fragment.xml文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffff00"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textview"
        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>

創建AnotherRightFragment類:

public class AnotherRightFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.another_right_fragment, container, false);
        return view;
    }
}

修改activity_main.xml文件:

<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:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
    
    <FrameLayout
        android:id="@+id/right_layout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

</LinearLayout>

在代碼中向FrameLayout裏添加內容,從而實現動態添加碎片的功能。

修改MainActivity中的代碼:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
        replaceFragment(new RightFragment());
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                replaceFragment(new AnotherRightFragment());
                break;
            default:
                break;
        }
    }

    private void replaceFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.right_layout, fragment);
        transaction.commit();
    }
}

上面代碼是當點擊左側的按鈕時,通過replaceFragment()方法將右邊的碎片替換成AnotherRightFragment。

總結動態添加碎片的步驟:

  • 創建待添加的碎片實例

  • 調用getSupportFragmentManager()方法來獲取FragmentManager

  • 通過調用beginTransaction()方法來開啓一個事務

  • 向容器內添加或替換碎片,一般使用replace()方法實現,需要傳入容器的id和待添加的碎片實例

  • 提交事務,調用commit()方法來完成

效果圖:

運行程序,效果圖如下:

4.2.3 在碎片中模擬返回棧

上面通過點擊按鈕添加一個碎片後,如果此時按下Back鍵程序就會直接退出。如果想要模範返回棧的效果,返回到上一個碎片,則需要在提交事務之前調用addToBackStack()方法。

private void replaceFragment(Fragment fragment) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.replace(R.id.right_layout, fragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

效果圖:

重新運行程序,效果圖如下:

4.2.4 碎片和活動之間進行通信

1. Activity調用Fragment方法

LeftFragment leftFragment = (LeftFragment) getSupportFragmentManager().findFragmentById(R.id.left_fragment);

2. Fragment調用Activity方法

MainActivity mainActivity = (MainActivity) getActivity();

獲取到相應的實例對象後,然後就可以直接調用相應的公用方法。

4.3 碎片的生命週期

碎片也有生命週期,並且它和Activity的生命週期很相似。

4.3.1 碎片的狀態和回調

1. 運行狀態

碎片可見,並且與它所關聯的活動正處於運行狀態時,該碎片也在運行狀態。

2. 暫停狀態

當一個活動進入暫停狀態時(由於另一個未佔滿屏幕的活動被添加到了棧頂),與它相關聯的可見碎片就會進入到暫停狀態。

3. 停止狀態

  • Activity進入停止狀態時,與它所關聯的碎片就會進入停止狀態。

  • 調用了FragmentTransaction的remove()、replace()方法,但在提交事務之前調用了addToBackStack()方法,此時碎片也會進入到停止狀態。

4. 銷燬狀態

  • Activity進入銷燬狀態時,與它所關聯的碎片就會進入銷燬狀態。

  • 調用了FragmentTransaction的remove()、replace()方法,但在提交事務之間沒有調用了addToBackStack()方法,此時碎片也會進入到銷燬狀態。

Android官方給出了Fragment完整的生命週期示意圖:

  • onAttach():碎片實例被關聯到活動實例

  • onCreate():創建碎片時,系統調用該方法

  • onCreateView():當碎片將要第一次繪製它的用戶界面時系統調用該方法

  • onActivityCreated:當宿主活動被創建,在onCreateView()方法之後調用該方法

  • onStart(): 碎片可見時調用該方法

  • onResume(): 碎片可交互時調用該方法

  • onPause(): 當首次表明用戶將要離開碎片時系統調用該方法

  • onStop(): 碎片將要被停止時調用

  • onDestroyView(): 調用該方法後,碎片將要被銷燬

  • onDestroy(): 該方法被用來清理碎片的狀態

4.3.2 體驗碎片的生命週期

省略…需要自己寫Demo去體驗!!!

4.4 動態加載佈局的技巧

Android可以根據設備的分辨率或者屏幕大小來動態加載佈局。

4.4.1 使用限定符

平板與手機最大的區別就是平板採用的雙頁模式,手機採用的是單頁模式。

在實際開發中,我們可以通過限定符讓程序的運行時動態的判斷是使用雙頁模式還是單頁模式。

修改activity_main文件:

<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:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

在res目錄下新建layout-large文件夾,並新建一個佈局,也叫activity_main.xml,代碼如下:

<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:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
    
    <fragment
        android:id="@+id/right_fragment"
        android:name="com.example.fragmenttest.RightFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"/>

</LinearLayout>

layout/activity_main佈局只包含了一個碎片,即單頁模式,而layout-large/activity_main佈局包含了兩個碎片,即雙頁模式。

large就是一個限定符,那些屏幕被認爲是large的設備就會自動加載layout-large文件夾下的佈局,而屏幕小的設備則會加載layout文件夾下的佈局。

效果圖:

單頁模式運行:

雙頁模式運行:

Android中有一些常見的限定符,參考下表:

4.4.2 使用最小寬度限定符

上面使用了large限定符,large屬於一個模糊的概念,如果我們想具體一點,到底多大是叫large,此時我們就可以使用最小寬度限定符(Smallest-width Qualifier)。

最小寬度限定符允許我們對屏幕的寬度指定一個最小值(以dp爲單位),然後以這個值爲臨界點,屏幕寬度大於這個值的設備就加載一個佈局,屏幕寬度小於這個值的設備就加載另一個佈局。

在res目錄下新建一個layout-sw600dp文件夾,然後新建activity_main.xml文件。

當程序運行在屏幕寬度大於600dp的設備上時,就會加載layout-sw600dp/activity_main佈局;當程序運行在屏幕寬度小於600dp的設備上時,則加載默認的layout/activity_main佈局。

4.5 碎片的最佳實踐——一個簡易版的新聞應用

代碼已上傳到我的github上,需要的朋友可以點擊如下鏈接查看:

碎片的最佳實踐——一個簡易版的新聞應用

運行效果圖:

單頁模式:

雙頁模式:

非常感謝您的耐心閱讀,希望我的文章對您有幫助。歡迎點評、轉發或分享給您的朋友或技術羣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章