構建靈活的界面

在設計支持各種屏幕尺寸的應用時,你可以在不同的佈局配置中重複使用 Fragment ,以便根據相應的屏幕空間提供更出色的用戶體驗。

例如,一次只顯示一個 Fragment 可能就很適合手機這種單窗格界面,但在平板電腦上,你可能需要設置並列的 Fragment,因爲平板電腦的屏幕尺寸較寬闊,可向用戶顯示更多信息。

這裏寫圖片描述

圖 1: 兩個 Fragment,顯示在不同尺寸屏幕上同一 Activity 的不同配置中。在較寬闊的屏幕上,兩個 Fragment 可並列顯示;在手機上,一次只能顯示一個 Fragment,因此必須在用戶導航時更換 Fragment。

利用 FragmentManager 類提供的方法,你可以在運行時添加、移除和替換 Activity 中的 Fragment,以便爲用戶提供一種動態體驗。

在運行時向 Activity 添加 Fragment

你可以在 Activity 運行時向其添加 Fragment,而不用像上一課中介紹的那樣,使用 < fragment > 元素在佈局文件中爲 Activity 定義 Fragment。如果你打算在 Activity 運行週期內更改 Fragment,就必須這樣做。

要執行添加或移除 Fragment 等事務,你必須使用 FragmentManager 創建一個 FragmentTransaction,後者可提供用於執行添加、移除、替換以及其他 Fragment 事務的 API。

如果 Activity 中的 Fragment 可以移除和替換,你應在調用 Activity 的 onCreate() 方法期間爲 Activity 添加初始 Fragment(s)。

在處理 Fragment(特別是在運行時添加的 Fragment )時,請謹記以下重要規則:必須在佈局中爲 Fragment 提供 View 容器,以便保存 Fragment 的佈局。

下面是上一課所示佈局的替代佈局,這種佈局一次只會顯示一個 Fragment。要用一個 Fragment 替換另一個 Fragment, Activity 的佈局中需要包含一個作爲 Fragment 容器的空 FrameLayout。

請注意,該文件名與上一課中佈局文件的名稱相同,但佈局目錄沒有 large 這一限定符。因此,此佈局會在設備屏幕小於“large”的情況下使用,原因是尺寸較小的屏幕不適合同時顯示兩個 Fragment。

res/layout/news_articles.xml:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

在 Activity 內部,使用 Support Library API 調用 getSupportFragmentManager() 以獲取 FragmentManager,然後調用 beginTransaction() 創建 FragmentTransaction,同時調用 add() 添加 Fragment。

你可以使用同一個 FragmentTransaction 對 Activity 執行多 Fragment 事務。當你準備好進行更改時,必須調用 commit()。

例如,下面介紹瞭如何爲上述佈局添加 Fragment :

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;

    public class MainActivity extends FragmentActivity {
        &Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);

            // 確認 Activity 使用的佈局版本包含
            // fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // 不過,如果我們要從先前的狀態還原,
                // 則無需執行任何操作而應返回
                // 否則就會得到重疊的 Fragment 。
                if (savedInstanceState != null) {
                    return;
                }

                // 創建一個要放入 Activity 佈局中的新 Fragment 
                HeadlinesFragment firstFragment = new HeadlinesFragment();

                // 如果此 Activity 是通過 Intent 發出的特殊指令來啓動的,
                // 請將該 Intent 的 extras 以參數形式傳遞給該 Fragment 
                firstFragment.setArguments(getIntent().getExtras());

                // 將該 Fragment 添加到“fragment_container”FrameLayout 中
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit();
            }
        }
    }

由於該 Fragment 已在運行時添加到 FrameLayout 容器中,而不是在 Activity 佈局中通過 < fragment > 元素進行定義,因此該 Activity 可以移除和替換這個 Fragment 。

用一個 Fragment 替換另一個 Fragment

替換 Fragment 的步驟與添加 Fragment 的步驟相似,但需要調用 replace() 方法,而非 add()。

請注意,當你執行替換或移除 Fragment 等 Fragment 事務時,最好能讓用戶向後導航和“撤消”所做更改。要通過 Fragment 事務允許用戶向後導航,你必須調用 addToBackStack(),然後再執行 FragmentTransaction。

注意:當你移除或替換 Fragment 並向返回堆棧添加事務時,已移除的 Fragment 會停止(而不是銷燬)。如果用戶向後導航,還原該 Fragment,它會重新啓動。如果你沒有向返回堆棧添加事務,那麼該 Fragment 在移除或替換時就會被銷燬。

替換 Fragment 的示例:

    // 創建 Fragment 併爲其添加一個參數,用來指定應顯示的文章
    ArticleFragment newFragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putInt(ArticleFragment.ARG_POSITION, position);
    newFragment.setArguments(args);

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

    // 將 fragment_container View 中的內容替換爲此 Fragment ,
    // 然後將該事務添加到返回堆棧,以便用戶可以向後導航
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);

    // 執行事務
    transaction.commit();

addToBackStack() 方法可接受可選的字符串參數,來爲事務指定獨一無二的名稱。除非你打算使用 FragmentManager.BackStackEntry API 執行高級 Fragment 操作,否則無需使用此名稱。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章