这两天看了鸿洋大神的一篇关于ViewPager的推送,将其中的内容实现了下,过程中依旧踩坑不断,现在将填坑过程中的一些解决方法及理解记录一下。
ViewPager+PageAdapter
这是最基本的一种使用,要注意的是,PagaAdapter中有4个必须要重写的方法:
- getCount()
需要在viewpager中显示的对象数。
- isViewFromObject(View view, Object object)
直接return view==object;
- instantiateItem(ViewGroup container, int position)
要显示页面的初始化,其中return 语句中返回的object才是显示的内容。
- destroyItem(ViewGroup container, int position, Object object)
页面不是当前显示页面,也不是缓存页面,则回调该方法将其销毁。
ViewPager+FragmentPagerAdapter+TabLayout
用FragmentPagerAdapter的话,通常重写两个方法:
@Override
public Fragment getItem(int position) {
return list.get(position);
}
@Override
public int getCount() {
return list.size();
}
这里要注意的是,在new一个FragmentPagerAdapter时,需要传入一个FragmentManager,而这个FragmentManager是v4包中的,它的获取方式是
fragmentManager=getSupportFragmentManager();
而不是常用的 fragmentManager1=getFragmentManager();
我们用fragment时因为它能实现更多的逻辑,降低耦合性,而用view的话,也可以进行某些实现,但是代码就会全部冗杂在一块儿,后面如果修改就会很麻烦。
我们可以结合TabLayout实现页面滑动时上层标签的内容改变。
1.重写adapter中的getPageTitle()方法,它的返回值即标签中的内容
@Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:return "first";
case 1:return "second";
case 2:return "third";
default:return "hello";
}
}
这里case后不需要break了,因为用了return离开了该方法,也不需要用switch语句后用return,因为有default语句,不管是否有符合的值,都会return。
2.将ViewPager与TabLayout“绑定”
tabLayout.setupWithViewPager(viewPager);
当两者绑定后,其实是TabLayout通过ViewPager调用它的getPageTitle()方法来实现联动。
这里有一个知识点,就是FragmentPagerAdapter与FragmentStatePagerAdapter的区别,鸿洋大神写得很清楚了,这里就直接引用了。
FragmentPagerAdapter:对于不再需要的 fragment,选择调用 onDetach() 方法,仅销毁视图,并不会销毁 fragment 实例。
FragmentStatePagerAdapter:会销毁不再需要的 fragment,当当前事务提交以后,会彻底的将 fragmeng 从当前 Activity 的FragmentManager 中移除,state 标明,销毁时,会将其 onSaveInstanceState(Bundle outState) 中的 bundle 信息保存下来,当用户切换回来,可以通过该 bundle 恢复生成新的 fragment,也就是说,你可以在 onSaveInstanceState(Bundle outState) 方法中保存一些数据,在 onCreate 中进行恢复创建。
总结起来就是:当页面多的时候,就用FragmentStatePagerAdapter来省内存;页面少时,就用FragmentPagerAdapter来提升效率。
ViewPager的轮播
1.自动无限轮播
即在一定时间间隔时更换页面,这里通过handler就可以实现了。
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what==0011){
viewPager.setCurrentItem((viewPager.getCurrentItem()+1)%list.size());
this.sendEmptyMessageDelayed(0011,1000);
}
}
};
handler.sendEmptyMessageDelayed(0011,1000);
2.手动实现轮播
所谓的手动实现轮播,就是在最后一个页面往后滑动时可以回到第一个页面。而这也是与banner很大的一个区别,banner是可以直接实现的,而viewpager我们则需要写一些内容。
先上代码:
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view=list.get(position%list.size());
ViewGroup viewGroup=(ViewGroup)view.getParent();
if (viewGroup!=null) viewGroup.removeView(view);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {}
因为我们要实现“从尾到头”的变化,而这个变化也不知道要多少次,所以我们就通过getCount()给了一个绝对大的值来实现。
重点在instantiateItem()中,如果我们按照之前的写法,即
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view=list.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(list.get(position));
}
我们会发现当往回滑动的时候,程序会崩掉,这是因为图片第一次加载了,当往回滑动,它再一次加载时,我们需要在它的父类中先将该object删除了,再重新加载新的对象。
这里还有一个要注意的是,因为我们在instantiateItem()中已经对图片的移除做了处理了,所以就不需要重写destroyItem()方法了。如果我们按照上面的代码重写了该方法,会发现显示的内容为空。
ViewPager中滑动页面后文字改变
我们可以选择在instantiateItem()中根据当前的position来获得文字内容,但这样滑动时会显得比较生硬,所以可以选择将textview与ViewPager分离开,通过对ViewPager添加监听,来达到页面变化时文字内容改变。
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
@Override
public void onPageSelected(int position) {
textView.setText(titles[position%titles.length]);
}
@Override
public void onPageScrollStateChanged(int state) {}
});
同屏显示多个页面
这里的同屏显示多个页面,并不是ViewPager中显示多个,实际上它还是只显示了一个页面,但是我们通过它与其父布局及它与前后两个页面之间的margin来达到3个页面(部分页面)的同时出现。需要用到的几个方法:
- clipChildren=”false”
设定值为false后,才可以使得子view的裁剪不受影响
- viewPager.setPageMargin( )
设置每两个页面之间的margin
- viewPager.setOffscreenPageLimit( )
设置需要显示在屏幕上的页面的个数
这里贴出xml的布局:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">
<android.support.v4.view.ViewPager
android:id="@+id/viewpagers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:layout_gravity="center"
android:layout_marginLeft="60dp"
android:layout_marginRight="60dp" />
</LinearLayout>
当我们实现多屏显示后,如果觉得单调,想让页面随着滑动的位置不同,改变图片的透明度,可以调用viewPager.setPageTransformer( )来增加特效。
viewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
private static final float DEFAULT_MIN_ALPHA = 0.5f;
private float mMinAlpha = DEFAULT_MIN_ALPHA;
@Override
public void transformPage(View page, float position) {
if (position < -1)
{
page.setAlpha(mMinAlpha);
} else if (position <= 1)
{ // [-1,1]
if (position < 0) //[0,-1]
{
float factor = mMinAlpha + (1 - mMinAlpha) * (1 + position);
page.setAlpha(factor);
} else//[1,0]
{
float factor = mMinAlpha + (1 - mMinAlpha) * (1 - position);
page.setAlpha(factor);
}
} else
{ // (1,+Infinity]
page.setAlpha(mMinAlpha);
}
}
});
关于这个动画,还可以看下大神的另一篇文章
巧用ViewPager 打造不一样的广告轮播切换效果