今天面试头条,有个面试官问我,怎么实现Banner 轮播?
我当时解答就是,记录一个count,每次滑动一次,把count ++, 然后我们设置当前的索引的时候,count % banner的size。
面试官说,这样的话,会有一个问题,就是ViewPage 的最后一个页面动画到第一个页面的时候,会执行反向滚动,导致动画异常的问题。
问我怎么解决,我当时没有想出来特别好的方法。
后来,我有时间了,就研究一下,怎么处理这个情况。
其实按照我说的实现方式,会有两个问题:
1.解决最后一个动画到第一个的时候,反向滚动动画异常的问题。
2.你不能左右手动的无限滑动,因为你的思路是元素只有三个。那么滑动到最后一个的时候,你发现不能滑动了。
解决方法
如果我们有三个banner, 那么他的数据长度就是3. 我们假定数据数组为list1
为了实现无线循环,那么我们在PageAdapter 的 getCount 方法,返回的长度是原来的长度(3) + 2, 这样我就会有5 个长度。我们就会有一个数组list2
当instantiateItem 方法调用的时候,如果我们发现position 是0,那么我们就生成list1的最后一个元素对应的页面,如果position 是最后一个位置,那么我们就返回list1第一个元素对应的页面。否则的话,我们就返回list position -1 位置对应的页面。
当我们滑动到最后一个元素的时候,我们偷偷的把当前的index 变为0.这样就又可以从0开始轮播。因为最后一个元素的页面其实和第一个页面是一样的。所以可以没有动画偷偷的替换。
package com.example.widget;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
/**
* =======================================================================================
* 作 者:caoxinyu
* 创建日期:2020/4/29.
* 类的作用:
* 修订历史:
* =======================================================================================
*/
public class BannerViewAdapter extends PagerAdapter{
public PagerAdapter mInnerPageAdapter;
public BannerViewAdapter(PagerAdapter innerPageAdapter) {
mInnerPageAdapter = innerPageAdapter;
}
@Override
public int getCount() {
//只有两个以上 才能滚动
if (mInnerPageAdapter.getCount() > 1) {
return mInnerPageAdapter.getCount() + 2;
}else {
return mInnerPageAdapter.getCount();
}
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
if (position == 0) {
return mInnerPageAdapter.instantiateItem(container,mInnerPageAdapter.getCount()-1);
}else if (position == getCount()-1){
return mInnerPageAdapter.instantiateItem(container,0);
}
//因为我们在前面和最后都加了一个元素 所以 当是中间的位置的时候,position 是要减1 给内部的adapter 去创建对象
return mInnerPageAdapter.instantiateItem(container,position-1);
}
@Override
public void notifyDataSetChanged() {
mInnerPageAdapter.notifyDataSetChanged();
super.notifyDataSetChanged();
}
//必须要重写的方法 不知道为什么
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
mInnerPageAdapter.destroyItem(container,position,object);
}
}
git 项目地址:
https://github.com/TomasYu/androidTest
详见项目的BannerViewPagerFragment 页面实现
参考:
https://juejin.im/post/5d08b8a251882559ed71d789