1. ViewPager概述
ViewPager的典型实现效果如上所示,关于ViewPager主要涉及到以下内容:
- ViewPager简单使用
- ViewPager + TabLayout + Fragment使用
- ViewPager 轮播图的使用(指示器、标题、自动轮播、首尾循环)
- ViewPager 的切换效果(PageTransformer)
- ViewPager 切换效果进阶
1.1 介绍
ViewPager
就是一个简单的页面切换组件,我们可以往里面填充多个View,然后我们可以左 右滑动,从而切换不同的View
这里简单归结如下:
- ViewPager 是 v4 包中的一个类。
- ViewPager 类直接继承了 ViewGroup 类,它是一个容器类,可以在其中添加其他的 view 。
- 类似于 ListView,也有自己的适配器,用来填充数据页面
这里先简单一览常用的动态设置方法:
-
setAdapter()
设置适配器 -
setOffscreenPageLimit()
设置缓存的页面个数,默认是 1 -
setCurrentItem()
跳转到特定的页面 -
setOnPageChangeListener(..)
设置页面滑动时的监听器(现在API中建议使用addOnPageChangeListener(..)
) -
setPageTransformer()
设置页面切换时的动画效果 -
setPageMargin()
设置不同页面之间的间隔 -
setPageMarginDrawable()
设置不同页面间隔之间的装饰图也就是 divide ,要想显示设置的图片,需要同时设置setPageMargin()
ViewPager也需要一个Adapter将View与viewPager进行绑定,其有一个特定的Adapter——PagerAdapter
关于ViewPager建议用Fragment来填充。提供了两个专用Adapter:FragmentPagerAdapter和FragmentStatePagerAdapter
-
FragmentPagerAdapter
和PagerAdapter一样,只会缓存当前的Fragment以及左边一个,右边 一个,即总共会缓存3个Fragment
-
FragmentStatePagerAdapter
当Fragment对用户不可见,整个Fragment销毁,仅保留Fragment状态。页面重新显示,生成新的页面。
总结:
页面较少选择FragmentPagerAdapter,页面多且复杂选FragmentStatePagerAdapter
2. ViewPager简单使用
2.1 PagerAdapter使用
PagerAdapter 是抽象的类,所以使用时只能使用它的子类,实现子类必须实现一下四个方法,(一般重写getCount()
与isViewFromObject()
即可)
-
getCount()
获取窗体界面数
-
destroyItem()
页面非当前显示页非缓存页调用此方法销毁。确保在
finishUpdate()
返回时视图能够被移除。 -
instantiateItem()
显示或缓存的页面调用此方法进行布局初始化
-
isViewFromObject()
判断是否由对象生成界面,建议直接返回
return view == object;
简单示例:
- 编写View布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFBA55"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个Page"
android:textColor="#000000"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
- 自定义的PagerAdapter
public class MyPagerAdapter extends PagerAdapter {
private ArrayList<View> viewLists;
public MyPagerAdapter() {
}
public MyPagerAdapter(ArrayList<View> viewLists) {
super();
this.viewLists = viewLists;
}
@Override
public int getCount() {
return viewLists.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
return view == o;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
container.addView(viewLists.get(position));
return viewLists.get(position);
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView(viewLists.get(position));
}
}
- 修改MainActivity
public class MainActivity extends AppCompatActivity {
private ViewPager vpager_one;
private ArrayList<View> aList;
private MyPagerAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vpager_one = (ViewPager) findViewById(R.id.vpager_one);
aList = new ArrayList<View>();
LayoutInflater li = getLayoutInflater();
aList.add(li.inflate(R.layout.view_one,null,false));
aList.add(li.inflate(R.layout.view_two,null,false));
aList.add(li.inflate(R.layout.view_three,null,false));
aList.add(li.inflate(R.layout.view_one,null,false));
mAdapter = new MyPagerAdapter(aList);
vpager_one.setAdapter(mAdapter);
}
}
2.1.1 标题栏
这里标题栏,即随着ViewPager滑动而滑动的标题。这里有两个:
-
PagerTitleStrip
内容是普通文字
-
PagerTabStrip
内容是带有下划线以及可以点击文字切换页面
二者的区别是:布局不同
使用方法很简单,简单示例如下:
- PagerTitleStrip所在Activity布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#CCFF99"
android:gravity="center"
android:text="PagerTitleStrip效果演示"
android:textColor="#000000"
android:textSize="18sp" />
<android.support.v4.view.ViewPager
android:id="@+id/vpager_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pagertitle"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_gravity="top"
android:textColor="#000000" />
</android.support.v4.view.ViewPager>
</LinearLayout>
- PagerTabStrip所在布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="35dp"
android:background="#C0C080"
android:gravity="center"
android:text="PagerTabStrip效果演示"
android:textSize="18sp" />
<android.support.v4.view.ViewPager
android:id="@+id/vpager_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<android.support.v4.view.PagerTabStrip
android:id="@+id/pagertitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top" />
</android.support.v4.view.ViewPager>
</LinearLayout>
- 自定义PagerAdapter,这里需要额外重写一个方法:
getPageTitle()
,用来设置标题。
public class MyPagerAdapter extends PagerAdapter {
private ArrayList<View> viewLists;
private ArrayList<String> titleLists;
public MyPagerAdapter() {
}
public MyPagerAdapter(ArrayList<View> viewLists, ArrayList<String> titleLists) {
super();
this.viewLists = viewLists;
this.titleLists = titleLists;
}
@Override
public int getCount() {
return viewLists.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
return view == o;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
container.addView(viewLists.get(position));
return viewLists.get(position);
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView(viewLists.get(position));
}
// 获取顶部标题
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return titleLists.get(position);
}
}
- 修改MainActivity
public class MainActivity extends AppCompatActivity {
private ViewPager vpager_two;
private ArrayList<View> aList;
private ArrayList<String> sList;
private MyPagerAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_three);
vpager_two = (ViewPager) findViewById(R.id.vpager_three);
aList = new ArrayList<View>();
LayoutInflater li = getLayoutInflater();
aList.add(li.inflate(R.layout.view_one,null,false));
aList.add(li.inflate(R.layout.view_two,null,false));
aList.add(li.inflate(R.layout.view_three,null,false));
sList = new ArrayList<String >();
sList.add("橘黄");
sList.add("淡黄");
sList.add("浅棕");
mAdapter = new MyPagerAdapter(aList, sList);
vpager_two.setAdapter(mAdapter);
}
}
2.1.2 循环轮播

ViewPager循环轮播的原理如上图所示。
- 假定有三个数据1、2、3,我们将其拼接成3、1、2、3、1的数据结构。
- 初始化数据,ViewPager指向1这个位置,如果左滑,当前显示List<0>这个页面,让ViewPager重新指向红色3的位置(
List<length - 2>
) - 如果当前位置在红3页,如果右滑,显示
List<length - 1>
页面,重新setCurrentItem
到红1页。
简单示例:
- Acitivity的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
- ViewPager页面布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="10dp"
android:textColor="#000000"/>
</FrameLayout>
- 自定义Adapter,继承PagerAdapter
public class MyPagerAdapter extends PagerAdapter {
private List<View> viewList;
private List<Integer> drawableList;
public MyPagerAdapter() {
}
public MyPagerAdapter(List<View> viewList, List<Integer> drawableList) {
this.viewList = viewList;
this.drawableList = drawableList;
}
@Override
public int getCount() {
return viewList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
return view == o;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View view = viewList.get(position);
ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
imageView.setImageResource(drawableList.get(position));
TextView textView = (TextView) view.findViewById(R.id.text_view);
textView.setText(String.valueOf(position));
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView(viewList.get(position));
}
}
- 设定滑动监听器
public class CycleScrollOnPageChangeListener implements ViewPager.OnPageChangeListener {
private List<View> viewList;
private ViewPager viewPager;
public CycleScrollOnPageChangeListener() {
}
public CycleScrollOnPageChangeListener(List<View> viewList, ViewPager viewPager) {
this.viewList = viewList;
this.viewPager = viewPager;
}
@Override
public void onPageSelected(int i) {
}
@Override
public void onPageScrolled(int i, float v, int i1) {
if (v == 0) {
if (i == 0) {
viewPager.setCurrentItem(viewList.size() - 2, false);
} else if(i == (viewList.size() - 1)) {
viewPager.setCurrentItem(1,false);
}
}
}
@Override
public void onPageScrollStateChanged(int i) {
}
}
- 修改MainActivity
public class MainActivity extends AppCompatActivity {
private int[] drawableIds = new int[] {R.drawable.a, R.drawable.b, R.drawable.c,
R.drawable.d, R.drawable.e};
private List<View> viewList = new ArrayList<>();
private ViewPager viewPager;
private List<Integer> drawableList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.view_pager);
initData();
createPageItems();
viewPager.setAdapter(new MyPagerAdapter(viewList, drawableList));
viewPager.addOnPageChangeListener(new CycleScrollOnPageChangeListener(viewList, viewPager));
viewPager.setCurrentItem(viewList.size() - 2, false);
viewPager.setVisibility(View.INVISIBLE);
viewPager.postDelayed(new Runnable() {
@Override
public void run() {
viewPager.setVisibility(View.VISIBLE);
// 设置初始 position
viewPager.setCurrentItem(1, false);
}
}, 100);
}
private void initData() {
drawableList = new ArrayList<Integer>();
drawableList.add(drawableIds[drawableIds.length - 1]);
for (int id : drawableIds) {
drawableList.add(id);
}
drawableList.add(drawableIds[0]);
}
public void createPageItems() {
LayoutInflater inflater = LayoutInflater.from(this);
for (int i = 0; i < drawableList.size(); i++) {
View view = inflater.inflate(R.layout.viewpager_item1, null);
viewList.add(view);
}
}
}
代码解读:
-
滑动监听器
OnPagerChageListener
这个接口需要实现三个方法:-
onPageScrollStateChanged()
状态改变时调用,其中参数有三种状态(0,1,2),状态为1,表示正在滑动;为2表示滑动完毕;为0表示手指离开屏幕。
-
onPageScrolled()
页面滑动调用此方法,滑动停止前,此方法一直被调用。其中有三个参数:
- 第一个参数:当前页面及点击滑动的页面
- 第二个参数:当前页面偏移百分比
- 第三个参数:当前页面偏移的像素位置
-
onPageSelected()
页面跳转完后调用,参数是你当前选中页面的Position(位置编号)
-
2.2 FragmentPagerAdapter与FragmentStatePagerAdapter
PagerAdapter是抽象类,其子类FragmentPagerAdapter也是抽象类。其是PagerAdapter的一种实现,其中每一个缓存的页面Fragment都会保存到Fragment Manager
中。适合页面数量较少时。
FragmentStatePagerAdapter
也是抽象类,也是PagerAdapter的一种实现。当Fragment不可见,销毁整个Fragment,仅保留Fragment状态,适合页面数量多且复杂的情况。
自定义这两个适配器,需要重写两个方法:getItem()
和getCount()
简单示例:
- 自定义适配器
public class FmPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
public FmPagerAdapter(List<Fragment> fragmentList, FragmentManager fm) {
super(fm);
this.fragmentList = fragmentList;
}
@Override
public int getCount() {
return fragmentList != null && !fragmentList.isEmpty() ? fragmentList.size() : 0;
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
}
- 修改MainActivity
viewPager = (ViewPager) findViewById(R.id.view_pager);
FmPagerAdapter adapter = new FmPagerAdapter(fragmentList, getSupportFragmentManager());
viewPager.setAdapter(adapter);
示例2:
public abstract class FixedPagerAdapter<T> extends FragmentStatePagerAdapter {
private List<ItemObject> mCurrentItems = new ArrayList<>();
public FixedPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
while (mCurrentItems.size() <= position) {
mCurrentItems.add(null);
}
Fragment fragment = (Fragment) super.instantiateItem(container, position);
ItemObject object = new ItemObject(fragment, getItemData(position));
mCurrentItems.set(position, object);
return object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
mCurrentItems.set(position, null);
super.destroyItem(container, position, ((ItemObject) object).fragment);
}
@Override
public int getItemPosition(Object object) {
ItemObject itemObject = (ItemObject) object;
if (mCurrentItems.contains(itemObject)) {
T oldData = itemObject.t;
int oldPosition = mCurrentItems.indexOf(itemObject);
T newData = getItemData(oldPosition);
if (equals(oldData, newData)) {
return POSITION_UNCHANGED;
} else {
int newPosition = getDataPosition(oldData);
return newPosition >= 0 ? newPosition : POSITION_NONE;
}
}
return POSITION_UNCHANGED;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, ((ItemObject) object).fragment);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return super.isViewFromObject(view, ((ItemObject) object).fragment);
}
public abstract T getItemData(int position);
public abstract int getDataPosition(T t);
public abstract boolean equals(T oldD, T newD);
public class ItemObject {
public Fragment fragment;
public T t;
public ItemObject(Fragment fragment, T t) {
this.fragment = fragment;
this.t = t;
}
}
}
public class DemoActivity extends AppCompatActivity {
private static final int INCREASE = 4;
private FixedPagerAdapter mFixedPagerAdapter;
private List<String> mTitles;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_not_update);
TextView updateTv = (TextView) findViewById(R.id.tv_update);
updateTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateFragments();
}
});
initFragments();
}
private void initFragments() {
mTitles = new ArrayList<>();
for (int i = 0; i < INCREASE; i++) {
mTitles.add(String.valueOf(i));
}
ViewPager viewPager = (ViewPager) findViewById(R.id.vp_content);
mFixedPagerAdapter = new MyFixedPagerAdapter(getSupportFragmentManager(), mTitles);
viewPager.setAdapter(mFixedPagerAdapter);
}
private void updateFragments() {
mTitles.clear();
mTitles.add("3");
mTitles.add("2");
mFixedPagerAdapter.notifyDataSetChanged();
}
private class MyFixedPagerAdapter extends FixedPagerAdapter<String> {
private List<String> mTitles;
public MyFixedPagerAdapter(FragmentManager fragmentManager, List<String> titles) {
super(fragmentManager);
mTitles = titles;
}
@Override
public String getItemData(int position) {
return mTitles.size() > position ? mTitles.get(position) : null;
}
@Override
public int getDataPosition(String s) {
return mTitles.indexOf(s);
}
@Override
public boolean equals(String oldD, String newD) {
return TextUtils.equals(oldD, newD);
}
@Override
public Fragment getItem(int position) {
return LogcatFragment.newInstance(mTitles.get(position));
}
@Override
public int getCount() {
return mTitles.size();
}
}
}
网友评论