目录
在运行时为 Activity 添加 Fragment
替换 Fragment
在设计支持各种屏幕尺寸的应用时,您可以在不同的布局配置中重复使用 Fragment,以根据可用的屏幕空间优化用户体验。
例如,在手机设备上,由于采用单窗格界面,因此可能一次只显示一个 Fragment 比较合适。相反,在平板电脑上,由于屏幕尺寸较大,因此您可能想要设置并排显示的 Fragment,以向用户显示更多信息。
利用 FragmentManager
类提供的方法,您可以在运行时为 Activity 添加、移除和替换 Fragment,从而营造出动态的用户体验。
图 1. 同一 Activity 的两个 Fragment,采用不同的配置显示在不同屏幕尺寸的设备上。在较大的屏幕上,两个 Fragment 同屏并排显示,但在手机设备上,同屏仅显示一个 Fragment,因此用户必须通过切换屏幕进行浏览。
您可以在 Activity 运行时为其添加 Fragment,而不用像上一课中介绍的那样,使用
元素在布局文件中为 Activity 定义 Fragment。如果您计划在 Activity 的生命周期内更改 Fragment,就需要采用这种方法。
要执行添加或移除 Fragment 等事务,您必须使用 FragmentManager
创建一个 FragmentTransaction
,后者将提供添加、移除、替换 Fragment 以及执行其他 Fragment 事务所需的 API。
如果您的 Activity 允许移除和替换 Fragment,应在 Activity 的 onCreate()
方法执行期间为其添加初始 Fragment。
在处理 Fragment 时(尤其是在运行时添加 Fragment 时),需遵循的一个重要原则是,您的 Activity 布局必须包含一个可以插入 Fragment 的容器 View
。
下面是上一课所示布局的替代布局,该布局一次只显示一个 Fragment。为了能够将一个 Fragment 替换为另一个 Fragment,Activity 的布局包含一个用来充当 Fragment 容器的空 FrameLayout
。
请注意,虽然文件名与上一课中的布局文件相同,但布局目录没有 large
限定符,因此该布局会在设备屏幕尺寸小于“large”时使用,因为这种尺寸的屏幕无法同时容纳两个 Fragment。
res/layout/news_articles.xml:
在您的 Activity 内,使用支持库 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);
// 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 布局中进行定义,因此可以从 Activity 中移除该 Fragment,并将其替换为其他 Fragment。
替换 Fragment 的过程与添加 Fragment 类似,但需要调用 replace()
方法,而非 add()
。
请注意,当您执行替换或移除 Fragment 等 Fragment 事务时,通常最好让用户能够回退并“撤消”更改。要让用户能够回退所执行的 Fragment 事务,您必须先调用 addToBackStack()
,然后再提交 FragmentTransaction
。
注意:当您移除或替换一个 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 操作,否则不需要该名称。