安卓训练-开始-使用 Fragment 构造动态 UI-构造灵活的 UI

构造灵活的 UI

当你为支持大范围的屏幕尺寸设计你的应用时,你可以在不同的布局配置中重用你的 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,你必须使用 FragmentManager 创建一个FragmentTransaction,它提供了添加,删除,替换和执行其他 fragment 事务的 API。

如果你的 activity 允许 fragment 被删除或替换,你应该在 activity 的 onCreate()方法中添加初始 fragment 到 activity。

一条处理 fragment—特别是你运行时添加的 fragment—的重要规则是在包含 fragment 的布局的布局中 fragment 必须要有一个容器View

下面的布局是上一课中每次只显示一个 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 中,使用支持库 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 操作。

 
 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。