先看效果图
可实现自动轮播以及手动左右无限滑动
实现的原理是在自己的准备的banner图的首尾再加上两张图,中间的adcde是我们需要轮播的图片,首尾则为特意加上去的,目的是使滑动更加的平滑,并不参与实际的操作。
当页面从编号1滑动到0时,将页面设置为5;
当页面从编号5滑动到6时,将页面设置为1;.
为了防止页面停顿,突然跳到下一页的情况,将设置页面的代码放到finishUpdate(@NonNull ViewGroup container)方法中去实现,该方法会在view创建和销毁之前调用。
具体实现如下:
布局文件代码:
自定义视图BannerPager:
public class BannerPager extends RelativeLayout implements View.OnClickListener {
private static final String TAG = "BannerPager";
private Context mContext; // 声明一个上下文对象
private ViewPager vp_banner; // 声明一个翻页视图对象
private RadioGroup rg_indicator; // 声明一个单选组对象
private List mViewList = new ArrayList(); // 声明一个图像视图队列
private int mInterval = 2000; // 轮播的时间间隔,单位毫秒
public BannerPager(Context context) {
this(context, null);
}
public BannerPager(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
initView();
}
// 初始化视图
private void initView() {
// 根据布局文件banner_pager.xml生成视图对象
View view = LayoutInflater.from(mContext).inflate(R.layout.banner_pager, null);
// 从布局文件中获取名叫vp_banner的翻页视图
vp_banner = view.findViewById(R.id.vp_banner);
// 从布局文件中获取名叫rg_indicator的单选组
rg_indicator = view.findViewById(R.id.rg_indicator);
addView(view); // 将该布局视图添加到横幅轮播条
}
// 开始广告轮播
public void start() {
// 延迟若干秒后启动滚动任务
mHandler.postDelayed(mScroll, mInterval);
}
// 停止广告轮播
public void stop() {
// 移除滚动任务
mHandler.removeCallbacks(mScroll);
}
// 设置广告轮播的时间间隔
public void setInterval(int interval) {
mInterval = interval;
}
// 设置广告图片队列
public void setImage(ArrayList imageList) {
int dip_15 = Utils.dip2px(mContext, 15);
// 根据图片队列生成图像视图队列
for (int i = 0; i < imageList.size(); i++) {
Integer imageID = imageList.get(i);
ImageView iv = new ImageView(mContext);
iv.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
iv.setScaleType(ImageView.ScaleType.FIT_XY);
iv.setImageResource(imageID);
iv.setOnClickListener(this);
mViewList.add(iv);
}
// 设置翻页视图的图像翻页适配器
vp_banner.setAdapter(new ImageAdapater());
// 给翻页视图添加简单的页面变更监听器
vp_banner.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int currentPosition = 1;
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int position) {
if (position == mViewList.size() - 1) {
// 设置当前值为1
currentPosition = 1;
} else if (position == 0) {
// 如果索引值为0了,就设置索引值为倒数第二个
currentPosition = mViewList.size() - 2;
} else {
currentPosition = position;
}
setButton(currentPosition);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
// 根据图片队列生成指示按钮队列
for (int i = 0; i < imageList.size(); i++) {
RadioButton radio = new RadioButton(mContext);
radio.setLayoutParams(new RadioGroup.LayoutParams(dip_15, dip_15));
radio.setGravity(Gravity.CENTER);
radio.setButtonDrawable(R.drawable.indicator_selector);
rg_indicator.addView(radio);
// 如果是第一或者最后一张图,隐藏指示按钮
if (i == 0 || i == imageList.size() - 1) {
Bitmap a = null;
radio.setButtonDrawable(new BitmapDrawable(a));
}
}
// 设置翻页视图默认显示第一页
vp_banner.setCurrentItem(1);
// 默认高亮显示第一个指示按钮
setButton(1);
}
// 设置选中单选组内部的哪个单选按钮
private void setButton(int position) {
((RadioButton) rg_indicator.getChildAt(position)).setChecked(true);
}
private Handler mHandler = new Handler(); // 声明一个处理器对象
// 定义一个滚动任务
private Runnable mScroll = new Runnable() {
@Override
public void run() {
scrollToNext(); // 滚动广告图片
// 延迟若干秒后继续启动滚动任务
mHandler.postDelayed(this, mInterval);
}
};
// 滚动到下一张广告图
public void scrollToNext() {
// 获得下一张广告图的位置
int index = vp_banner.getCurrentItem() + 1;
if (index >= mViewList.size() - 1) {
index = 1;
}
// 设置翻页视图显示指定位置的页面
vp_banner.setCurrentItem(index);
}
// 定义一个图像翻页适配器
private class ImageAdapater extends PagerAdapter {
// 获取页面项的个数
public int getCount() {
return mViewList.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
// 从容器中销毁指定位置的页面
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViewList.get(position));
}
//无论是创建view添加到容器中 还是 销毁view 都是在此方法结束之后执行的
@Override
public void finishUpdate(@NonNull ViewGroup container) {
super.finishUpdate(container);
int position = vp_banner.getCurrentItem();
if (position == 0) {
position = mViewList.size() - 2;
vp_banner.setCurrentItem(position, false);
} else if (position == mViewList.size() - 1) {
position = 1;
vp_banner.setCurrentItem(position, false);
}
}
// 实例化指定位置的页面,并将其添加到容器中
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViewList.get(position));
return mViewList.get(position);
}
}
@Override
public void onClick(View v) {
// 获取翻页视图当前页面项的序号
int position = vp_banner.getCurrentItem();
// 触发点击监听器的onBannerClick方法
mListener.onBannerClick(position);
}
// 设置广告图的点击监听器
public void setOnBannerListener(BannerClickListener listener) {
mListener = listener;
}
// 声明一个广告图点击的监听器对象
private BannerClickListener mListener;
// 定义一个广告图片的点击监听器接口
public interface BannerClickListener {
void onBannerClick(int position);
}
}
activity代码:
private void init() {
// 获取横幅轮播条的布局参数
ViewGroup.LayoutParams params = mbannerPager.getLayoutParams();
params.height = (int) (Utils.getScreenWidth(getActivity()) * 250f / 640f);
// 设置横幅轮播条的布局参数
mbannerPager.setLayoutParams(params);
// 设置横幅轮播条的广告图片队列
mbannerPager.setImage(ImageList.getDefault());
// 设置横幅轮播条的广告点击监听器
mbannerPager.setOnBannerListener(this);
// 开始广告图片的轮播滚动
mbannerPager.start();
}
上面为最初的代码,大体功能都已实现,现补充手指滑动时轮播停止功能,只需在自定义试图中为ViewPager加上手势触摸监听器即可!在手指滑动时停止轮播,抬起时开启轮播!
vp_banner.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
stop();
break;
case MotionEvent.ACTION_UP:
start();
break;
default:
break;
}
return false;
}
});
源码地址://download.csdn.net/download/qq_41824185/12017775