1. 程式人生 > >Android官方開發文件Training系列課程中文版:使用Fragment構建動態UI之構建靈活的UI

Android官方開發文件Training系列課程中文版:使用Fragment構建動態UI之構建靈活的UI

當設計應用程式時需要支援尺寸較大的寬屏裝置時,可以基於可用的螢幕空間在不同的佈局中配置並重新使用fragment來提升使用者體驗。

舉個例子,手持裝置在同一時間可能只適合展示一個介面,相反的,你可能希望在平板裝置上一邊一個Fragment,因為平板有更寬的介面用來展示更多的資訊。


上圖中:兩個Fragment,利用同一個Activity在不同的螢幕尺寸中展示出不同的介面效果。在大螢幕中,兩個fragment一邊一個,但是在手持裝置上,只能在同一時間內放置一個fragment,所以只能在使用者使用的時候使用替換的方式來展示另一個fragment。

類FragmentManager支援在執行時新增、刪除、替換fragment,以便提供更靈活的體驗。

在執行時新增Fragment到Activity中

正如上節課展示的那樣,我們可以通過在佈局檔案中新增< fragment>標籤的方式定義fragment,不過,我們還可以在activity執行的時候新增fragment到activity中。如果你計劃在activity的生命週期內改變fragment的話,那麼這項功能就很有必要了。

如果要執行類似新增、刪除fragment的這種事務,必須通過使用FragmentManager建立一個事務物件FragmentTransaction,它提供了新增、刪除、替換和其它fragment相關事務的功能。

如果activity允許fragment可以移除或者替換,那麼必須在onCreate方法內初始化fragment並新增到activity中。

在處理fragment的時候有很重要的一條規則,尤其是在新增fragment的時候,就是activity必須包含一個容器View物件,以便fragment物件可以新增到這個容器中。

下面這個佈局就是上一節課同時只顯示一個fragment更改過後的佈局,為了可以替換fragment,activity的佈局需要包含一個空的FrameLayout,當做fragment的容器。

注意,檔案的名稱還是和上節課中佈局的名字相同,但是佈局的資料夾目錄名稱則不再包含”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中呼叫getSupportFragmentManager()方法獲得支援庫中的FragmentManager物件,然後呼叫這個物件的beginTransaction()方法建立FragmentTransaction事務物件,通過這個事務物件的add()方法新增fragment。

你還可以使用FragmentTransaction事務物件執行多個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);
        // Check that the activity is using the layout version with
        // the fragment_container FrameLayout
        if (findViewById(R.id.fragment_container) != null) {
            // However, if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (savedInstanceState != null) {
                return;
            }
            // Create a new Fragment to be placed in the activity layout
            HeadlinesFragment firstFragment = new HeadlinesFragment();

            // In case this activity was started with special instructions from an
            // Intent, pass the Intent's extras to the fragment as arguments
            firstFragment.setArguments(getIntent().getExtras());

            // Add the fragment to the 'fragment_container' FrameLayout
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, firstFragment).commit();
        }
    }
}

因為fragment在執行時被新增到了FrameLayout中,所以activity可以使用另一個不同的fragment來替換它,或者可以移除它。

替換Fragment

替換fragment的過程和新增的過程很相似,只是需要使用replace()方法而不是add()方法。

記住,在執行fragment事務的時候,比如替換或者移除,經常需要適當的允許使用者可以通過返回撤銷改變。為了通過fragment事務允許使用者做到這一點,必須在FragmentTransaction事務提交之前呼叫addToBackStack()方法。

Note:當你通過移除或者替換將fragment作為事務新增到回退棧的時候,那個被移除的fragment會進入停止狀態(沒有被銷燬)。如果使用者通過返回還原了fragment,那麼它就會重新啟動。如果沒有新增事務到回退棧,那麼fragment在移除或者替換的時候會被銷燬。

這是個替換fragment的例子:

// Create fragment and give it an argument specifying the article it should show
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();

addToBackStack()方法有一個可選的字串引數,這個引數可以用來指定事務的唯一標示名稱。這個名稱不是必須的,除非你計劃通過FragmentManager.BackStackEntry API執行更佳的fragment操作。