當設計程序來支持各種不一樣的屏幕尺寸時,可以在不同的布局中重用fragment來根據可用的屏幕大小來優化用戶體驗。
例如,在手機上可能使用一個fragment來使用單窗口用戶體驗比較合適。但是,你可能想在平板上邊靠邊的設置兩個fragment因為有更寬的屏幕向用戶展示更多信息。
圖1.兩個fragment,同一個activity在不同的屏幕大小上的不同展現形式。在大屏幕上,兩個fragment邊靠邊,但是在手機設備上,一次只顯示一個fragment因此fragment在用戶切換的時候替換另一個。
為了創建動態的體驗, FragmentManager類提供了方法可以在運行時添加,刪除,替換activity中的fragment。
在運行時向activity添加fragment
不僅僅可以在activity布局文件中定義fragment(前面介紹了使用<fragment>元素),也可以在activity運行時加入fragment。如果計划在activity運行時改變fragment,這個很有必要。
要處理添加刪除fragment,可以使用FragmentManager來創建一個FragmentTransation,它提供了API來添加,替換和fragment的其他事務。
如果activity允許fragment刪除或者替換,應該在activity的onCreate()方法中添加fragment的初始化信息。
處理fragment有一個重要的規則,特別是在運行時添加的fragment:fragment在布局中必須有一個View容器。
下面的布局是上一篇中布局的一個變形,這里一次只顯示一個fragment。為了用一個fragment替換另一個,這個activity的布局包含一個空的FrameLayout作為fragment的容器。
這個文件名和前面一篇中布局的文件名是一樣的,但是布局文件夾沒有large標識,所以這個布局使用在小屏幕上因為小屏幕不需要同時顯示兩個fragment。
res/layout/news_articles.xml:
1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:id="@+id/fragment_container" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" />
在activity中,使用Support Library中的API getSupportFragmentManager()來獲得FragmentManager.然后調用beginTransaction()來創建一個FragmentTransaction再調用add()添加一個fragment。
可以使用一個FragmentTransaction來處理多個activity的fragment rransaction。當准備好執行這些改變后,調用commit()。
例如,這里展示了如何把fragment加到前一個布局上:
1 import android.os.Bundle; 2 import android.support.v4.app.FragmentActivity; 3 4 public class MainActivity extends FragmentActivity { 5 @Override 6 public void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.news_articles); 9 10 11 //檢查activity的布局是使用fragment_container FrameLayout的版本 12 if (findViewById(R.id.fragment_container) != null) { 13 14 // 但是,如果是從前一個狀態恢復的話 15 // 我們不需要做任何事情,直接返回就行了,否則就會重疊fragments。 16 if (savedInstanceState != null) { 17 return; 18 } 19 20 //創建一個Fragment實例 21 HeadlinesFragment firstFragment = new HeadlinesFragment(); 22 23 //有可能activity是從Intent中的特殊指令創建的, 24 //把Intent的extras當參數傳遞給fragment 25 firstFragment.setArguments(getIntent().getExtras()); 26 27 // 把fragment加入到'fragment_container' FrameLayout 28 getSupportFragmentManager().beginTransaction() 29 .add(R.id.fragment_container, firstFragment).commit(); 30 } 31 } 32 }
因為fragment是在運行時加入到FrameLayout的(不是在activity的布局文件中用<fragment>定義的),activity就可以移出這個fragment然后用一個不同的替換它。
用一個fragment替換另一個
換掉一個fragment的方法和添加一個相似,但是需要使用replace()方法,而不是add()。
記住當執行fragment切換時,例如添加或者刪除,經常要允許用戶切換回去來恢復這些改變。為了允許用戶在fragment切換時切換回去,應該在提交FragmentTransaction之前調用addToBackStack()。
注意:當移除或者替換一個fragment然后加到切換的返回堆棧中時,被移除的fragment是Stopped狀態(並不是Destroyed)。如果用戶切換回去來恢復fragment,它就重啟。如果沒有把它加到返回堆棧中,fragment被移除或者替換時就銷毀了。
用一個fragment替換另一個的例子:
1 //創建一個fragment,然后把應該展示的文章的參數傳給它 2 ArticleFragment newFragment = new ArticleFragment(); 3 Bundle args = new Bundle(); 4 args.putInt(ArticleFragment.ARG_POSITION, position); 5 newFragment.setArguments(args); 6 7 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 8 9 //用這個fragment替換掉fragment_container view 中的東西, 10 //然后把transaction加到返回堆棧中,這樣用戶就可以切換回去了 11 transaction.replace(R.id.fragment_container, newFragment); 12 transaction.addToBackStack(null); 13 14 //提交transaction 15 transaction.commit();
addToBackStack()方法帶一個可選的字符串參數,用來指定一個唯一的transaction名字。這個名字並不是必需的除非需要用FragmentManager.BackStackEntryAPI的一些特使操作。
上一篇:Android - 用Fragments實現動態UI - 創建Fragment
下一篇:Android - 用Fragments實現動態UI - 和其他Fragments通信