ViewPager
类:public class ViewPager
继承自 ViewGroup
定义:布局管理器允许用户左滑右滑含有数据的pages.
使用:只需要提供一个PagerAdapter
的实现来产生视图显示的pages.
ViewPager 最常结合 Fragment
使用,这是提供和管理每个页面的生命周期最便利的途径,也是一种最常见的用法,并且API提供了可以用来实现的标准适配器及其示例: FragmentPagerAdapter和
FragmentStatePagerAdapter
; 其每个类中都够一个简单的示例说明如何使用它构建一个完整的用户界面.
用 ViewPager.DecorView
注解注释的views被作为view pagers 'decor'的一部分.每个 decor view's位置可以通过其属性 android:layout_gravity
被控制. 例如:
<android.support.v4.view.ViewPager android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.PagerTitleStrip android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" /> </android.support.v4.view.ViewPager>
使用ViewPager的更多信息, 阅读 Creating Swipe Views with Tabs.
PagerTitleStrip
类public class PagerTitleStrip
继承自 ViewGroup
定义:PagerTitleStrip是一个 ViewPager
当前,下一个,上一个页面的非交互式指示器.
作用:在XML layout中作为ViewPager widget的一个子视图 .
使用:把他作为ViewPager的一个子控件添加到布局文件中 ,并且设置它的 android:layout_gravity 为TOP 或者 BOTTOM 将其固定到 ViewPager的顶部或底部. 其title是由 ViewPager的适配器实现的 getPageTitle(int)
供给.
关于交互式的指示器,看 PagerTabStrip
.
PagerTabStrip
类public class PagerTabStrip
继承自 PagerTitleStrip
定义:PagerTabStrip是一个 ViewPager
当前,下一个,上一个页面的交互式指示器.
作用:在XML layout中作为ViewPager widget的一个子视图 .
使用: 把他作为ViewPager的一个子控件添加到布局文件中 ,并且设置它的 android:layout_gravity 为TOP 或者 BOTTOM 将其固定到 ViewPager的顶部或底部. 其title是由 ViewPager的适配器实现的 getPageTitle(int)
供给.
关于非交互式的指示器,看 PagerTitleStrip
.
PagerAdapter
抽象类public abstract class PagerAdapter
继承自 Object
定义:提供填充 ViewPager
内的页面适配器的基类 ,你也许更喜欢使用它的更具体实现: FragmentPagerAdapter
或者 FragmentStatePagerAdapter
.
使用:实现PagerAdapter时, 最少也必须重写下面列出的这些方法:
instantiateItem(ViewGroup, int)
destroyItem(ViewGroup, int, Object)
getCount()
isViewFromObject(View, Object)
AdapterViews
.用到的adapter中,PagerAdapter是最普遍的 .ViewPager 使用回调来处理在更新过程中的步骤,而不是直接使用视图回收机制. 如果需要,PagerAdapter可以实现视图回收的一种形式,或者使用一个管理page视图的更复杂的方法,比如 Fragment transactions:每个 page都是由其Fragment实现.
ViewPager是通过一个key对象与每个page 关联,而不是直接与Views 一块运行.这个 key是用来跟踪并且唯一标识给定的page,独立于其在 adapter中的位置. 向PagerAdapter方法的一个回调startUpdate(ViewGroup)
表示这个 ViewPager中的内容即将发生变化. 接下来 instantiateItem(ViewGroup, int)
and/or destroyItem(ViewGroup, int, Object)
会有一个或更多的回调, 并且会通过调用 finishUpdate(ViewGroup)
表明变化接受 . 在 finishUpdate
返回的同一时间,与key 对象关联的由 instantiateItem
返回的视图,应该被添加到传递这些方法的父ViewGroup ,并且 关联传递给 destroyItem
keys的视图应该被移除. 方法 isViewFromObject(View, Object)
表示 a page View是否关联了这个被给的 key对象.
一个很简单的 PagerAdapter可以选择使用自身 the page Views作为 key 对象, 创建后从 instantiateItem(ViewGroup, int)
返回并且添加到父 ViewGroup. 发挥匹配作用的 destroyItem(ViewGroup, int, Object)
会从父ViewGroup移除这个视图,并且 isViewFromObject(View, Object)会作为
return view == object;
实现
PagerAdapter支持数据集的变化.数据集变化必须发生在主线程 并且必须通过调用 notifyDataSetChanged()
结束,类似于 BaseAdapter
派生的AdapterView adapters.数据集的变化可能会涉及到 pages 的添加,移除,或位置变化. 通过adapter实现 getItemPosition(Object)
.可以让ViewPager保存当时正处于的状态
FragmentPagerAdapter
抽象类:public abstract class FragmentPagerAdapter
继承自: PagerAdapter
定义:FragmentPagerAdapter是 PagerAdapter
的一种实现,
作用:将每个 page作为 Fragment
放在fragment manager 里,这样,用户可以返回到上一个page.
使用场景:这种pager(翻页器)很适用于大部分的有较少或固定数量的fragmentpage,内容尽量静态化的 fragments切换页面, 比如一组tab.用户访问的 每个fragment page会被保存在内存中 , 即使当不可见时视图层次会被销毁. 这会导致应用占用太多资源,因为fragment 实例可以支持随意数量的state. 如果有大量 pages, 应该考虑使用FragmentStatePagerAdapter
.
使用:使用 FragmentPagerAdapter时, 其所属ViewPager必须具有一个有效的 ID set.
在开发中,继承FragmentPagerAdapter的子类需要实现 getItem(int)
和 getCount()
来创建需要的adapter
FragmentStatePagerAdapter
抽象类public abstract class FragmentStatePagerAdapter
继承自 PagerAdapter
包中的位置:android.support.v4.app.FragmentStatePagerAdapter
定义:FragmentPagerAdapter也是 PagerAdapter
的一种实现,
作用:使用fragment去管理每一个页面.这个类也可以处理保存和恢复 fragment的state.
使用场景:这种的pager(翻页器)更适用于含有大量pages的情景,作用很类似 a list view.当pages 对于用户处于不可见,其整个fragment会被销毁,仅保持 fragment被保存的状态.这个特点让pager占用更少内存关联每个出现过的page ,因此,与 FragmentPagerAdapter
相比,页面切换时,资源利用更科学.
使用:同使用 FragmentPagerAdapter一样,使用FragmentStatePagerAdapter时, 其所属ViewPager必须具有一个有效的 ID set.
同样,在开发中,继承FragmentStatePagerAdapter的子类只需要实现 getItem(int)
和 getCount()
来创建需要的adapter.
FragmentPagerAdapter和FragmentStatePagerAdapter的实现示例比较:
The R.layout.fragment_pager
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip" android:gravity="center_horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1"> </android.support.v4.view.ViewPager> <LinearLayout android:orientation="horizontal" android:gravity="center" android:measureWithLargestChild="true" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0"> <Button android:id="@+id/goto_first" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/first"> </Button> <Button android:id="@+id/goto_last" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/last"> </Button> </LinearLayout> </LinearLayout>
The R.layout.fragment_pager_list
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:drawable/gallery_thumb"> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical|center_horizontal" android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/hello_world"/> <!-- The frame layout is here since we will be showing either the empty view or the list view. --> <FrameLayout android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" > <!-- Here is the list. Since we are using a ListActivity, we have to call it "@android:id/list" so ListActivity will find it --> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:drawSelectorOnTop="false"/> <!-- Here is the view to show if the list is emtpy --> <TextView android:id="@android:id/empty" android:layout_width="match_parent" android:layout_height="match_parent" android:textAppearance="?android:attr/textAppearanceMedium" android:text="No items."/> </FrameLayout> </LinearLayout>
FragmentPagerAdapter实现 pager 中含有一组fragments的示例:
public class FragmentPagerSupport extends FragmentActivity { static final int NUM_ITEMS = 10; MyAdapter mAdapter; ViewPager mPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_pager); mAdapter = new MyAdapter(getSupportFragmentManager()); mPager = (ViewPager)findViewById(R.id.pager); mPager.setAdapter(mAdapter); // 监测按钮clicks. Button button = (Button)findViewById(R.id.goto_first); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { mPager.setCurrentItem(0); } }); button = (Button)findViewById(R.id.goto_last); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { mPager.setCurrentItem(NUM_ITEMS-1); } }); } public static class MyAdapter extends FragmentPagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return NUM_ITEMS; } @Override public Fragment getItem(int position) { return ArrayListFragment.newInstance(position); } } public static class ArrayListFragment extends ListFragment { int mNum; /** * 创建一个新的CountingFragment实例, 提供 "num" * 作为一个 argument. */ static ArrayListFragment newInstance(int num) { ArrayListFragment f = new ArrayListFragment(); // 输入 num 作为一个 argument. Bundle args = new Bundle(); args.putInt("num", num); f.setArguments(args); return f; } /** * 当 creating, 从实例的arguments恢复其数目 . */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mNum = getArguments() != null ? getArguments().getInt("num") : 1; } /** * The Fragment's UI 仅是一个显示实例数字的text view */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_pager_list, container, false); View tv = v.findViewById(R.id.text); ((TextView)tv).setText("Fragment #" + mNum); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Cheeses.sCheeseStrings)); } @Override public void onListItemClick(ListView l, View v, int position, long id) { Log.i("FragmentList", "Item clicked: " + id); } } }
FragmentStatePagerAdapter实现 pager 中含有一组fragments的示例:
public class FragmentStatePagerSupport extends Activity { static final int NUM_ITEMS = 10; MyAdapter mAdapter; ViewPager mPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_pager); mAdapter = new MyAdapter(getFragmentManager()); mPager = (ViewPager)findViewById(R.id.pager); mPager.setAdapter(mAdapter); // Watch for button clicks. Button button = (Button)findViewById(R.id.goto_first); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { mPager.setCurrentItem(0); } }); button = (Button)findViewById(R.id.goto_last); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { mPager.setCurrentItem(NUM_ITEMS-1); } }); } public static class MyAdapter extends FragmentStatePagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return NUM_ITEMS; } @Override public Fragment getItem(int position) { return ArrayListFragment.newInstance(position); } } public static class ArrayListFragment extends ListFragment { int mNum; /** * Create a new instance of CountingFragment, providing "num" * as an argument. */ static ArrayListFragment newInstance(int num) { ArrayListFragment f = new ArrayListFragment(); // Supply num input as an argument. Bundle args = new Bundle(); args.putInt("num", num); f.setArguments(args); return f; } /** * When creating, retrieve this instance's number from its arguments. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mNum = getArguments() != null ? getArguments().getInt("num") : 1; } /** * The Fragment's UI is just a simple text view showing its * instance number. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_pager_list, container, false); View tv = v.findViewById(R.id.text); ((TextView)tv).setText("Fragment #" + mNum); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Cheeses.sCheeseStrings)); } @Override public void onListItemClick(ListView l, View v, int position, long id) { Log.i("FragmentList", "Item clicked: " + id); } } }