使用Tabs创建Swipe视图

编写:Lin-H - 原文:http://developer.android.com/training/implementing-navigation/lateral.html

Swipe View提供在同级屏幕中的横向导航,例如通过横向划屏手势切换的tab(一种称作横向分页的模式)。这节课会教你如何使用swipe view创建一个tab layout实现在tab之间切换,或显示一个标题条替代tab。

Swipe View 设计

在实现这些功能之前,你要先明白在Designing Effective Navigation, Swipe Views design guide中的概念和建议

实现Swipe View

你可以使用Support Library中的ViewPager控件在你的app中创建swipe view。ViewPager是一个子视图在layout上相互独立的布局控件(layout widget)。

使用ViewPager来设置你的layout,要添加一个<ViewPager>元素到你的XML layout中。例如,在你的swipe view中如果每一个页面都会占用整个layout,那么你的layout应该是这样:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.v4.view.ViewPager
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:id="@+id/pager"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent" />

要插入每一个页面的子视图,你需要把这个layout与PagerAdapter挂钩。有两种adapter(适配器)你可以用:

FragmentPagerAdapter

在同级屏幕(sibling screen)只有少量的几个固定页面时,使用这个最好。

FragmentStatePagerAdapter

当根据对象集的数量来划分页面,即一开始页面的数量未确定时,使用这个最好。当用户切换到其他页面时,fragment会被销毁来降低内存消耗。

例如,这里的代码是当你使用FragmentStatePagerAdapter来在Fragment对象集合中进行横屏切换:

  1. public class CollectionDemoActivity extends FragmentActivity {
  2. // 当被请求时, 这个adapter会返回一个DemoObjectFragment,
  3. // 代表在对象集中的一个对象.
  4. DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
  5. ViewPager mViewPager;
  6. public void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_collection_demo);
  9. // ViewPager和他的adapter使用了support library
  10. // fragments,所以要用getSupportFragmentManager.
  11. mDemoCollectionPagerAdapter =
  12. new DemoCollectionPagerAdapter(
  13. getSupportFragmentManager());
  14. mViewPager = (ViewPager) findViewById(R.id.pager);
  15. mViewPager.setAdapter(mDemoCollectionPagerAdapter);
  16. }
  17. }
  18. // 因为这是一个对象集所以使用FragmentStatePagerAdapter,
  19. // 而不是FragmentPagerAdapter.
  20. public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
  21. public DemoCollectionPagerAdapter(FragmentManager fm) {
  22. super(fm);
  23. }
  24. @Override
  25. public Fragment getItem(int i) {
  26. Fragment fragment = new DemoObjectFragment();
  27. Bundle args = new Bundle();
  28. // 我们的对象只是一个整数 :-P
  29. args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
  30. fragment.setArguments(args);
  31. return fragment;
  32. }
  33. @Override
  34. public int getCount() {
  35. return 100;
  36. }
  37. @Override
  38. public CharSequence getPageTitle(int position) {
  39. return "OBJECT " + (position + 1);
  40. }
  41. }
  42. // 这个类的实例是一个代表了数据集中一个对象的fragment
  43. public static class DemoObjectFragment extends Fragment {
  44. public static final String ARG_OBJECT = "object";
  45. @Override
  46. public View onCreateView(LayoutInflater inflater,
  47. ViewGroup container, Bundle savedInstanceState) {
  48. // 最后两个参数保证LayoutParam能被正确填充
  49. View rootView = inflater.inflate(
  50. R.layout.fragment_collection_object, container, false);
  51. Bundle args = getArguments();
  52. ((TextView) rootView.findViewById(android.R.id.text1)).setText(
  53. Integer.toString(args.getInt(ARG_OBJECT)));
  54. return rootView;
  55. }
  56. }

这个例子只显示了创建swipe view的必要代码。下面一节向你说明如何通过添加tab使导航更方便在页面间切换。

添加Tab到Action Bar

Action bar tab能给用户提供更熟悉的界面来在app的同级屏幕中切换和分辨。

使用ActionBar来创建tab,你需要启用NAVIGATION_MODE_TABS,然后创建几个ActionBar.Tab的实例,并对每个实例实现ActionBar.TabListener接口。例如在你的activity的onCreate()方法中,你可以使用与下面相似的代码:

  1. @Override
  2. public void onCreate(Bundle savedInstanceState) {
  3. final ActionBar actionBar = getActionBar();
  4. ...
  5. // 指定在action bar中显示tab.
  6. actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
  7. // 创建一个tab listener,在用户切换tab时调用.
  8. ActionBar.TabListener tabListener = new ActionBar.TabListener() {
  9. public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
  10. // 显示指定的tab
  11. }
  12. public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
  13. // 隐藏指定的tab
  14. }
  15. public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
  16. // 可以忽略这个事件
  17. }
  18. };
  19. // 添加3个tab, 并指定tab的文字和TabListener
  20. for (int i = 0; i < 3; i++) {
  21. actionBar.addTab(
  22. actionBar.newTab()
  23. .setText("Tab " + (i + 1))
  24. .setTabListener(tabListener));
  25. }
  26. }

根据你如何创建你的内容来处理ActionBar.TabListener回调改变tab。但是如果你是像上面那样,通过ViewPager对每个tab使用fragment,下面这节就会说明当用户选择一个tab时如何切换页面,当用户划屏切换页面时如何更新相应页面的tab。

使用Swipe View切换Tab

当用户选择tab时,在ViewPager中切换页面,需要实现ActionBar.TabListener来调用在ViewPager中的setCurrentItem()来选择相应的页面:

  1. @Override
  2. public void onCreate(Bundle savedInstanceState) {
  3. ...
  4. // Create a tab listener that is called when the user changes tabs.
  5. ActionBar.TabListener tabListener = new ActionBar.TabListener() {
  6. public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
  7. // 当tab被选中时, 切换到ViewPager中相应的页面.
  8. mViewPager.setCurrentItem(tab.getPosition());
  9. }
  10. ...
  11. };
  12. }

同样的,当用户通过触屏手势(touch gesture)切换页面时,你也应该选择相应的tab。你可以通过实现ViewPager.OnPageChangeListener接口来设置这个操作,当页面变化时当前的tab也相应变化。例如:

  1. @Override
  2. public void onCreate(Bundle savedInstanceState) {
  3. ...
  4. mViewPager = (ViewPager) findViewById(R.id.pager);
  5. mViewPager.setOnPageChangeListener(
  6. new ViewPager.SimpleOnPageChangeListener() {
  7. @Override
  8. public void onPageSelected(int position) {
  9. // 当划屏切换页面时,选择相应的tab.
  10. getActionBar().setSelectedNavigationItem(position);
  11. }
  12. });
  13. ...
  14. }

使用标题栏替代Tab

如果你不想使用action bar tab,而想使用scrollable tabs来提供一个更简短的可视化配置,你可以在swipe view中使用PagerTitleStrip

下面是一个内容为ViewPager,有一个PagerTitleStrip顶端对齐的activity的layout XML文件示例。单个页面(adapter提供)占据ViewPager中的剩余空间。

  1. <android.support.v4.view.ViewPager
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@+id/pager"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <android.support.v4.view.PagerTitleStrip
  7. android:id="@+id/pager_title_strip"
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:layout_gravity="top"
  11. android:background="#33b5e5"
  12. android:textColor="#fff"
  13. android:paddingTop="4dp"
  14. android:paddingBottom="4dp" />
  15. </android.support.v4.view.ViewPager>