构造灵活的 UI
这节课教你
- 在运行时添加 Fragment 到 Activity
- 替换 Fragment
你还需要阅读
试试
FragmentBasics.zip
当你为支持大范围的屏幕尺寸设计你的应用时,你可以在不同的布局配置中重用你的 fragment,根据可用的屏幕空间优化用户体验。
例如,在一个手持设备上,单栏用户界面中每次只显示一个 fragment 可能比较合适。相反地,在一个平板上,有更宽的屏幕尺寸展示更多的信息给用户,你可能并行地设置多个 fragment。
图 1. 两个 fragment,同一个 activity,在不同的屏幕尺寸上以不同的配置显示。在大屏幕上,两个 fragment 并行排列适合屏幕,但是在手持设备上,每次只有一个 fragment 适合,当用户导航时 fragment 必须相互替换。
FragmentManager
类提供了运行时添加 fragment 到 activity,从 activity 中删除 fragment,和在 activity 中替换 fragment的方法,使用这些方法你可以创建动态的用户体验。
在运行时添加 Fragment 到 Activity
不是在布局文件中为 activity 定义 fragment—像上一课所展示的使用
<fragment>
元素—你可以在运行时添加 fragment 到 activity。这是必须的,如果你想在 activity的生命周期中改变它的 fragment。
为了执行一个事务,比如添加或删除一个 fragment,你必须使用
创建一个
FragmentManagerFragmentTransaction
,它提供了添加,删除,替换和执行其他
fragment 事务的 API。
如果你的 activity 允许 fragment 被删除或替换,你应该在 activity 的
方法中添加初始 fragment 到 activity。
onCreate()
一条处理 fragment—特别是你运行时添加的 fragment—的重要规则是在包含 fragment 的布局的布局中 fragment 必须要有一个容器View
。
下面的布局是上一课中每次只显示一个 fragment 的布局的替代物。为了用一个 fragment 替换另一个,activity 的布局包含一个作为 fragment 的容器的空的FrameLayout
。
注意,文件名与上一课中的布局文件相同,但是布局目录没有
限定符,所以这个布局用于比 large 小的屏幕的设备,因为小屏幕不适合同时显示两个 fragment。
large
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 中,使用支持库 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 的附加数据作为参数传给 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 的过程与添加类似,但要用
replace()
方法而不是add()
。
记住,当你执行 fragment 事务,比如替换或删除一个 fragment,通常允许用户向后导航和"撤销"变化是恰当的。 为了允许用户在 fragment 事务中能向后导航,你必须在提交FragmentTransaction
前调用addToBackStack()
。
注意:当你删除或替换一个 fragment 并把事务添加到返回栈(back stack),删除的 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 替换 fragment_container 视图中的东西 // 并把事务添加到返回栈,让用户可以导航回来 transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // 提交事务 transaction.commit();
addToBackStack()
方法接收一个可选的字符串参数,这个参数为事务指定一个唯一名称。这个名称并不需要,除非你计划使用FragmentManager.BackStackEntry
API 执行一些高级的 fragment 操作。