跟Google学习Android开发-起始篇-用碎片构建一个动态的用户界面(3)
4.3 构建一个灵活的用户界面
当设计你的应用程序要支持大范围的屏幕尺寸时,你可以在不同的布局配置中重用碎片,来根据可用的屏幕空间优化用户体验。
例如,在手持设备上,它可能是适应来在一个单窗格用户界面一次只显示一个碎片。相反地,你可能要设置碎片并排地在具有更宽的屏幕尺寸的平板电脑上显示更多的信息给用户。
图1两个碎片,在不同的屏幕尺寸上同一个活动以不同的配置显示。在大屏幕上,两个碎片适合并排,但在手机设备上,适合在一次只有一个碎片,所以碎片必须在当用户浏览时互相代替。
FragmentManager类提供了一些方法,使您可以在活动运行时添加、移除和替换碎片,来创建一个动态的体验。
在运行时添加一个碎片到活动
不是在布局文件中定义活动的碎片——像上一课所示那样使用<fragment>
元素——你可以在活动的运期间添加一个碎片到活动。如果你打算在活动的生命过程中改变碎片,这是必要的。
执行添加或删除碎片之类的事务,您必须使用FragmentManager创建一个 FragmentTransaction,它提供添加、删除、替换以及执行其它碎片事务的API。
如果你的活动允许碎片被移除或者替换,你应该在活动 的onCreate()方法添加初始的碎片到活动。
处理碎片——尤其是那些你在运行时添加的碎片——的一个重要原则是,碎片在布局中必须有一个容器视图,碎片的布局将驻留在该视图中。
下面的布局是在上节课展示的一次只显示一个碎片的布局的一个替代方案。为了用另一个碎片替换一个碎片,活动的布局包含一个空的FrameLayout作为碎片容器。
注意文件名跟在上节课中的布局文件是一样的,但布局目录不会有large
标识符,所以这个布局在设备屏幕小于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" />
在您的活动内使用支持库API调用getSupportFragmentManager()得到一个 FragmentManager。然后调用BeginTransaction()创建一个FragmentTransaction并调用add()添加一个碎片。
您可以使用相同的FragmentTransaction对活动执行多个碎片事务。当你准备好提交变化时,你必须调用commit()方法。
例如,下面添加一个碎片到之前的布局的方法:‘
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();
}
}
}
由于碎片在运行时已被添加到FrameLayout容器——而不是在活动的布局使用<fragment>
元素定义它——活动可以移除碎片并用另一个不同的碎片替换它。
用另一个碎片替换碎片
替换一个碎片的过程跟添加一个类似,但需要replace()方法,而不是add() 。
请记住,当你执行碎片事务时,如替换或移除一个碎片,它通常应当允许用户导航回去并“撤消”变化。为了让用户可以在碎片事务导航回去,你必须在提交 FragmentTransaction之前调用addToBackStack()。
注意:当您移除或替换一个碎片,并添加事务到后退堆栈,被移除的碎片是停止的(而不是被销毁)。如果用户导航回去恢复碎片,它会重新启动。如果你不添加事务到后退堆栈,那么碎片在移除或替换时会被销毁。
用另一个碎片替换碎片的示例:
// 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来执行高级的碎片操作。