本文译自:http://developer.android.com/training/basics/fragments/fragment-ui.html
当要把应用程序设计成支持大多数屏幕尺寸的时候,你可以在不同的布局配置中复用你的Fragment,并基于可用的屏幕空间来优化用户体验。
例如,在手持设备上,它可能每次只适合显示一个Fragment作为用户界面。相反,在平板电脑上,你可能想要一组Fragment彼此相连,把更多的信息显示给用户。
图1.在不同屏幕尺寸上的同一个Activity中使用不同的配置来显示两个Fragment。在大屏幕上,两个Fragment彼此相连同时显示,但是在手持设备上,每次只会显示一个Fragment,因此在用户浏览时,两个Fragment必须交替的来显示。
为了创建动态的体验,FragmentManager类提供了在运行时添加、删除、替换Fragment的方法。
在运行是把一个Fragment添加给Activity
相比在布局文件中给Activity定义Fragment而言,你可以在Activity运行期间把Fragment添加给Activity。如果你打算在Activity生存期间来改变Fragment,这样做是必须。
要执行诸如添加或删除Fragment这样的事务处理,你必须使用FragmentManager来创建一个FragmentTransaction,它提供了添加、删除、替换以及其他Fragment事务处理的API。
如果你的Activity允许删除和替换Fragment,你应该在Activity的onCreate()方法执行期间把初始的Fragment添加给Activity。
处理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内部,调用getSupportFragmentManager()方法来获得支持类库API所使用的FragmentManager对象。然后调用beginTransaction()方法来创建FragmentTransaction,并调用add()方法来添加一个Fragment。
对于一个Activity,你可以使用相同的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 an instance of ExampleFragment
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是在运行时被添加到FragmentLayout容器中,而不是在Activity的布局中用<fragment>元素来定义的,所以该Activity可以删除该Fragment,并用另一个Fragment来替换它。
用另一个Fragment来替换
替换Fragment的过程与添加过程类似,但是它需要使用replace()方法而不是add()方法。
要记住,在执行Fragment事务时,如替换或删除,要适当的允许用户返回和取消改变。要允许用户返回Fragment事务,在你提交FragmentTransaction之前,你必须调用addToBackStack()方法。
注意:当你删除或替换一个Fragment,并把该事务添加到回退堆栈时,被删除的Fragment会被终止(而不是销毁)。如果用户返回来恢复该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操作,否则不需要指定这个唯一名称。