B:建立一个灵活的用户界面
为了你的应用可以支持大屏幕尺寸的手机,你可以根据不同的可利用空间,配置拥有可重复利用的Fragment的不同布局配置来优化你的用户体验。
例如,在手机上,只显示一个单独的Fragment,提供一个单面板的用户界面是合适的。相反,在平板电脑上你就想把Fragment一个挨一个的平排放在宽的屏幕上,给用户提供更多的信息。如下图:
注意:FragmentManager类提供了在程序运行时向Activity中添加、删除、替换Fragment的方法,这样你就可以创建动态的体验了。
B.a 在程序运行时添加一个Fragment到Activity中
和上一篇讲的在布局文件中使用<fragment>
元素讲Fragment添加到Activity中比,你可以在Activity运行期间给它添加Fragment,如果你想在Activity的生命周期期间改变Fragments,那么这么做是必须的。
为了完成一个添加或者删除Fragment的事务,你必须用Fragment来创建一个FragmentTransaction,它提供了添加、删除、替换以及其他一下处理Fragment的方法。如果你的Activity允许Fragments被删除或者替换,你必须在Activity的onCreate()方法里面添加它。
和Fragment打交道最重要的规则(特别是那些在程序运行的添加的)-就是Fragment必须在布局中拥有一个容器,Fragment的布局将属于它。
下面这个布局是上一篇中只显示一个Fragment的那个布局的替换着,为了用一个Fragment替换另一个,这个布局中包含了一个空的FrameLayout作为Fragment的容器。
可以看到文件名和上一篇中的是一样的,但是他所在的文件夹没有了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中,调用getSupportFragmentManager()来获得一个使用支持库中方法的FragmentManager。然后调用beginTransaction()来创建一个FragmentTransaction然后调用add()方法来添加一个Fragment。
你可以在一个FragmentTransaction下执行多次对fragment的操作,当你做好准备变化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 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();
}
}
}
因为这个fragment实在程序运行是添加到FrameLayout中的,而不是在Activity的布局中用<fragment>元素添加的,所以Activity可以用删除它,或者另一个fragment替换它。
B.b 用一个fragment替换现有的fragment
替换一个fragment的过程和添加的过程是一样的,只不过使用replace()方法替换add()方法。
值得记住的是当你操作fragment时,允许用户返回或者取消操作是经常适用的。为了让用户可以通过之前的操作返回从前,你必须在调用addToBackStack()方法在你提交FragmentTransaction前。
注意:当你移除或者替换一个fragment并且把这次操作放到后退栈中时,这个被移除的fragment的生命周期变为stop(而不是被销毁了)。如果用户返回来恢复这个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
提供的方法来对fragment进行一些高级的操作。