1page.title=构建灵活的界面 2trainingnavtop=true 3page.type=培训 4@jd:body 5 6 <div id="tb-wrapper"> 7 <div id="tb"> 8 <h2>本课程所教授的内容:</h2> 9 <ol> 10 <li><a href="#AddAtRuntime">在运行时向 Activity 添加 Fragment</a></li> 11 <li><a href="#Replace">用一个 Fragment 替换另一个 Fragment </a></li> 12 </ol> 13 14 <h2>你还应阅读以下内容:</h2> 15 <ul> 16 <li><a href="{@docRoot}guide/components/fragments.html"><code>fragment</code></a></li> 17 <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">支持平板电脑和手机</a></li> 18 </ul> 19 20 <h2>试试以下示例:</h2> 21 22 <div class="download-box"> 23 <a href="http://developer.android.com/shareables/training/FragmentBasics.zip" class="button">下载示例</a> 24 <p class="filename">FragmentBasics.zip</p> 25 </div> 26 27 </div> 28 </div> 29 30 31 <p>在设计支持各种屏幕尺寸的应用时,你可以在不同的布局配置中重复使用 Fragment ,以便根据相应的屏幕空间提供更出色的用户体验。</p> 32 33 <p>例如,一次只显示一个 Fragment 可能就很适合手机这种单窗格界面,但在平板电脑上,你可能需要设置并列的 Fragment,因为平板电脑的屏幕尺寸较宽阔,可向用户显示更多信息。</p> 34 35 <img src="{@docRoot}images/training/basics/fragments-screen-mock.png" alt="" /> 36 <p class="img-caption"><strong>图 1:</strong> 两个 Fragment,显示在不同尺寸屏幕上同一 Activity 的不同配置中。在较宽阔的屏幕上,两个 Fragment 可并列显示;在手机上,一次只能显示一个 Fragment,因此必须在用户导航时更换 Fragment。</p> 37 38 <p>利用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentManager.html">FragmentManager</a></code> 类提供的方法,你可以在运行时添加、移除和替换 Activity 中的 Fragment,以便为用户提供一种动态体验。</p> 39 40 41 42 <h2 id="AddAtRuntime">在运行时向 Activity 添加 Fragment</h2> 43 44 <p>你可以在 Activity 运行时向其添加 Fragment,而不用像<a href="creating.html">上一课</a>中介绍的那样,使用 <code><fragment></code> 元素在布局文件中为 Activity 定义 Fragment。如果你打算在 Activity 运行周期内更改 Fragment,就必须这样做。</p> 45 46 <p>要执行添加或移除 Fragment 等事务,你必须使用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentManager.html">FragmentManager</a></code> 创建一个 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html">FragmentTransaction</a></code>,后者可提供用于执行添加、移除、替换以及其他 Fragment 事务的 API。</p> 47 48 <p>如果 Activity 中的 Fragment 可以移除和替换,你应在调用 Activity 的 <code><a href="{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)">onCreate()</a></code> 方法期间为 Activity 添加初始 Fragment(s)。</p> 49 50 <p>在处理 Fragment(特别是在运行时添加的 Fragment )时,请谨记以下重要规则:必须在布局中为 Fragment 提供 <code><a href="{@docRoot}reference/android/view/View.html">View</a></code> 容器,以便保存 Fragment 的布局。</p> 51 52 <p>下面是<a href="creating.html">上一课</a>所示布局的替代布局,这种布局一次只会显示一个 Fragment。要用一个 Fragment 替换另一个 Fragment, Activity 的布局中需要包含一个作为 Fragment 容器的空 <code><a href="{@docRoot}reference/android/widget/FrameLayout.html">FrameLayout</a></code>。</p> 53 54 <p><em></em>请注意,该文件名与上一课中布局文件的名称相同,但布局目录没有 <code>large</code> 这一限定符。因此,此布局会在设备屏幕小于“large”的情况下使用,原因是尺寸较小的屏幕不适合同时显示两个 Fragment。<em></em></p> 55 56 <p><code>res/layout/news_articles.xml:</code></p> 57 <pre> 58 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 59 android:id="@+id/fragment_container" 60 android:layout_width="match_parent" 61 android:layout_height="match_parent" /> 62 </pre> 63 64 <p>在 Activity 内部,使用 Support Library API 调用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentActivity.html#getSupportFragmentManager()">getSupportFragmentManager()</a></code> 以获取 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentManager.html">FragmentManager</a></code>,然后调用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentManager.html#beginTransaction()">beginTransaction()</a></code> 创建 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html">FragmentTransaction</a></code>,同时调用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html#add(android.support.v4.app.Fragment, java.lang.String)">add()</a></code> 添加 Fragment。</p> 65 66 <p>你可以使用同一个 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html">FragmentTransaction</a></code> 对 Activity 执行多 Fragment 事务。当你准备好进行更改时,必须调用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html#commit()">commit()</a></code>。</p> 67 68 <p>例如,下面介绍了如何为上述布局添加 Fragment :</p> 69 70 <pre> 71 import android.os.Bundle; 72 import android.support.v4.app.FragmentActivity; 73 74 public class MainActivity extends FragmentActivity { 75 &Override 76 public void onCreate(Bundle savedInstanceState) { 77 super.onCreate(savedInstanceState); 78 setContentView(R.layout.news_articles); 79 80 // 确认 Activity 使用的布局版本包含 81 // fragment_container FrameLayout 82 if (findViewById(R.id.fragment_container) != null) { 83 84 // 不过,如果我们要从先前的状态还原, 85 // 则无需执行任何操作而应返回 86 // 否则就会得到重叠的 Fragment 。 87 if (savedInstanceState != null) { 88 return; 89 } 90 91 // 创建一个要放入 Activity 布局中的新 Fragment 92 HeadlinesFragment firstFragment = new HeadlinesFragment(); 93 94 // 如果此 Activity 是通过 Intent 发出的特殊指令来启动的, 95 // 请将该 Intent 的 extras 以参数形式传递给该 Fragment 96 firstFragment.setArguments(getIntent().getExtras()); 97 98 // 将该 Fragment 添加到“fragment_container”FrameLayout 中 99 getSupportFragmentManager().beginTransaction() 100 .add(R.id.fragment_container, firstFragment).commit(); 101 } 102 } 103 } 104 </pre> 105 106 <p>由于该 Fragment 已在运行时添加到 <code><a href="{@docRoot}reference/android/widget/FrameLayout.html">FrameLayout</a></code> 容器中,而不是在 Activity 布局中通过 <code><fragment></code> 元素进行定义,因此该 Activity 可以移除和替换这个 Fragment 。</p> 107 108 109 110 <h2 id="Replace">用一个 Fragment 替换另一个 Fragment </h2> 111 112 <p>替换 Fragment 的步骤与添加 Fragment 的步骤相似,但需要调用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html#replace(int, android.support.v4.app.Fragment)">replace()</a></code> 方法,而非 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html#add(android.support.v4.app.Fragment, java.lang.String)">add()</a></code>。</p> 113 114 <p>请注意,当你执行替换或移除 Fragment 等 Fragment 事务时,最好能让用户向后导航和“撤消”所做更改。要通过 Fragment 事务允许用户向后导航,你必须调用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html#addToBackStack(java.lang.String)">addToBackStack()</a></code>,然后再执行 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html">FragmentTransaction</a></code>。</p> 115 116 <p class="note"><strong>注意</strong>:当你移除或替换 Fragment 并向返回堆栈添加事务时,已移除的 Fragment 会停止(而不是销毁)。如果用户向后导航,还原该 Fragment,它会重新启动。如果你没有向返回堆栈添加事务,那么该 Fragment 在移除或替换时就会被销毁<em></em>。</p> 117 118 <p>替换 Fragment 的示例:</p> 119 120 <pre> 121 // 创建 Fragment 并为其添加一个参数,用来指定应显示的文章 122 ArticleFragment newFragment = new ArticleFragment(); 123 Bundle args = new Bundle(); 124 args.putInt(ArticleFragment.ARG_POSITION, position); 125 newFragment.setArguments(args); 126 127 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 128 129 // 将 fragment_container <code>View</code> 中的内容替换为此 Fragment , 130 // 然后将该事务添加到返回堆栈,以便用户可以向后导航 131 transaction.replace(R.id.fragment_container, newFragment); 132 transaction.addToBackStack(null); 133 134 // 执行事务 135 transaction.commit(); 136 </pre> 137 138 <p><code><a href="{@docRoot}reference/android/support/v4/app/FragmentTransaction.html#addToBackStack(java.lang.String)">addToBackStack()</a></code> 方法可接受可选的字符串参数,来为事务指定独一无二的名称。除非你打算使用 <code><a href="{@docRoot}reference/android/support/v4/app/FragmentManager.BackStackEntry.html">FragmentManager.BackStackEntry</a></code> API 执行高级 Fragment 操作,否则无需使用此名称。</p> 139 140