最近工作用到了一个banner控件,所以写篇文章记录下,功能很简单
本文介绍用一种简单的方式实现一个banner轮播控件
实现思路很简单,就是在viewpager的原始imageViewList的前后个各增加一个假数据。首先在原始数据的起始位置前面增加一个与最后一张图片一样的imageView,然后在原始数据最后增加一个与第一张原始数据相同的图片。
这样,在最后一张图片向右切换时,滑动过程中漏出来的是假的第一张图片,当这张图片完全展示出来之后,在将整个viewpager定位到下标为1的真正的第一张图片。同理,在由第一张图片向左切换时,漏出的是假的最后一张图片,当这张图片完全展示后快速将viewpager快速定位到下标位5的图片。viewpager的index切换使用了mPager.setCurrentItem(pageIndex, false);
这样用户肉眼无法看出来banner进行了切换
根据上面的思路需要在viewpager下标5->6切换、1->0切换的时候进行下标的特殊处理,这里主要结合了viewpager的onPageSelected回调和onPageScrollStateChanged回调
public void onPageSelected(int i) {
pageIndex = i;//i取值从0~6
final int imageViewSize = mImageViews.size();
if (FAKE_ITEM_COUNT == 2 && imageViewSize > 1) {
if (i == 0) {// 当视图在第一个时,将页面号设置为图片的最后一张
pageIndex = imageViewSize - FAKE_ITEM_COUNT;
} else if (i == mImageViews.size() - 1) {// 当视图在最后一个时,将页面号设置为图片的第一张
pageIndex = 1;
}
}
}
其中FAKE_ITEM_COUNT
是指假的2张图片,在onPageSelected计算好应该切换到的pageIndex后只需要在onPageScrollStateChanged中判断viewpager页面滑停后进行页面index设置即可
public void onPageScrollStateChanged(int i) {
if (i == ViewPager.SCROLL_STATE_IDLE) {
if (mPager.getCurrentItem() != pageIndex) {
mPager.setCurrentItem(pageIndex, false);
}
}
}
实现轮播的方式是通过handler延迟一段时间发消息,而handler的消息处理中只要去设置当前index+1即可
int position = mPager.getCurrentItem() + 1;
if (position >= mPager.getAdapter().getCount()) { // 滑到底就再滑到开头
position = 0;
}
mPager.setCurrentItem(position);
整个bannerview的代码如下,其他的功能可以在此基础上加
public class BannerView extends FrameLayout implements ViewPager.OnPageChangeListener {
private static final int MSG_AUTO_FLIP = 1001;
private static final int AUTO_FLIP_INTERVAL = 5000;
//多添加的2个item
protected int FAKE_ITEM_COUNT = 0;
protected List mImageViews = new ArrayList<>();
protected ViewPager mPager;
protected long mLastTouchUpTime;
private int pageIndex;
private Handler mHandler;
public BannerView(Context context) {
super(context);
initView();
}
public BannerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
startAutoFlip();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopAutoFlip();
}
private void initView() {
setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_AUTO_FLIP:
autoFlip();
startAutoFlip();
break;
default:
break;
}
}
};
mPager = new MyPager(getContext());
mPager.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mPager.setAdapter(new MyPagerAdapter());
mPager.addOnPageChangeListener(this);
addView(mPager, 0);
}
public void updateBannerView(ArrayList bannerViews, boolean isLoopable) {
FAKE_ITEM_COUNT = isLoopable ? 2 : 0;
if (bannerViews == null) {
mImageViews.clear();
} else {
mImageViews = (ArrayList) bannerViews.clone();
}
mPager.getAdapter().notifyDataSetChanged();
mPager.setCurrentItem(isLoopable && mImageViews.size() > 1 ? 1 : 0);
}
void autoFlip() {
// 距离用户最近一次触摸松开的时间在自动滑动间隔之内
if ((SystemClock.elapsedRealtime() - mLastTouchUpTime) < AUTO_FLIP_INTERVAL) {
return;
}
int position = mPager.getCurrentItem() + 1;
if (position >= mPager.getAdapter().getCount()) { // 滑到底就再滑到开头
position = 0;
}
mPager.setCurrentItem(position);
}
public void startAutoFlip() {
stopAutoFlip();
if (mImageViews.size() < 2) {
return;
}
mHandler.sendEmptyMessageDelayed(MSG_AUTO_FLIP, AUTO_FLIP_INTERVAL);
}
public void stopAutoFlip() {
mHandler.removeMessages(MSG_AUTO_FLIP);
}
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int i) {
pageIndex = i;
final int imageViewSize = mImageViews.size();
if (FAKE_ITEM_COUNT == 2 && imageViewSize > 1) {
if (i == 0) {// 当视图在第一个时,将页面号设置为图片的最后一张
pageIndex = imageViewSize - FAKE_ITEM_COUNT;
} else if (i == mImageViews.size() - 1) {// 当视图在最后一个时,将页面号设置为图片的第一张
pageIndex = 1;
}
}
}
@Override
public void onPageScrollStateChanged(int i) {
if (i == ViewPager.SCROLL_STATE_IDLE) {
if (mPager.getCurrentItem() != pageIndex) {
mPager.setCurrentItem(pageIndex, false);
}
}
}
public class MyPager extends ViewPager {
private GestureDetector mGestureDetector;
public MyPager(Context context) {
this(context, null);
}
public MyPager(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new MyGestureListener());
setFadingEdgeLength(0);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mLastTouchUpTime = SystemClock.elapsedRealtime();
if (mGestureDetector.onTouchEvent(ev)) {
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (Math.abs(distanceY) < Math.abs(distanceX)) {
return true;
}
return false;
}
}
}
class MyPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImageViews.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return (arg0 == arg1);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mImageViews.get(position).getParent() == null) {
container.addView(mImageViews.get(position));
}
return mImageViews.get(position);
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
demo下载地址如下,感兴趣的可以看下~
https://download.csdn.net/download/u010420435/10643548