Banner轮播图的无限循环轮播功能、手动滑动功能
轮播图实现:(假如5张图轮播)
1、在List中存好这5张图,传到ViewPager的Adapter中,相当于5张图片横铺在ViewPager控件中。
2、设置ViewPager一开始的起始位置为5*1000=5000,并用seletedBanner记录该位置。
3、在PagerAdapter中将其getCount方法返回Integer的最大值,让它向左向右滑都不会越界。
4、在PagerAdapter中必须对当前位置%5(由于5张图,%5结果在0-4之间,刚好是图片集合的下标,如5002%5=2,就是List[2]中的对象)。
5、ViewPager监听滚动事件,用seletedBanner记录新位置。
6、在onResume中开始轮播。
圆点实现:
1、在一个水平的布局中添加5个圆点View对象,并存入一个List中。
2、遍历圆点List,在ViewPager滚动回调中判断seletedBanner(当前位置)%5,则该得到的值为选中圆点,其他为未选中圆点。
其效果图:
实现步骤
1、自定义RelativeLayout,编写固定的构造方法
public class MyBannerView extends RelativeLayout implements View.OnTouchListener, ViewPager.OnPageChangeListener { public MyBannerView(Context context) { this(context, null); } public MyBannerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyBannerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //初始化工作 initBannerViews(context, attrs, defStyleAttr); } }
2、声明需要用到的变量
//轮播图控件 private ViewPager targetVp; //轮播图集合 private ArrayList<View> bannerList; //指示器图集合 private ArrayList<View> indicationList; //上下文 private Context context; //当前轮播图位置 private int selectedBanner; //提示轮播 private final static int BANNER_CHANGE = 0; //是否为网络图片加载,作用是:如果是网络图片加载就不滚动轮播图,让用户自己手动滑动轮播图 boolean isNetImg = false;
3、初始化用到的组件
private void initBannerViews(Context context, AttributeSet attrs, int defStyleAttr) { this.context = context; //初始化ViewPager targetVp = new ViewPager(context); targetVp.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); targetVp.setOnTouchListener(this); targetVp.setOnPageChangeListener(this); //添加到View中 addView(targetVp); }
4、提供方法加载图片和指示器
这里有两个方法,加载本地图片和加载网络图片,加载网络图片用到Glide第三方框架,Glide的学习可以查看我的博客
/** * 在本地Drawable中加载轮播图 * * @param activity * @param img_urls 轮播图drawable的ID */ public void initShowImageForLocal(Activity activity, int[] img_urls) { //指示器布局 LinearLayout ly_indication = new LinearLayout(activity); LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); //指示器边距 params.bottomMargin = 15; //指示器位置 params.addRule(ALIGN_PARENT_BOTTOM); params.addRule(CENTER_HORIZONTAL); //添加到View中 addView(ly_indication, params); //图片集合和指示器集合 bannerList = new ArrayList<View>(); indicationList = new ArrayList<View>(); for (int i = 0; i < img_urls.length; i++) { //初始化图片 ImageView iv = new ImageView(activity); iv.setScaleType(ImageView.ScaleType.FIT_XY); iv.setBackgroundResource(img_urls[i]); bannerList.add(iv); //初始化指示器 ImageView iv2 = new ImageView(activity); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); lp.setMargins(8, 0, 0, 0); iv2.setLayoutParams(lp); //初始化指示器默认为第一张高亮 if (i == 0) { iv2.setBackgroundResource(R.drawable.home_top_ic_point_on); } else { iv2.setBackgroundResource(R.drawable.home_top_ic_point_off); } indicationList.add(iv2); //添加到圆点布局 ly_indication.addView(iv2); } //初始化轮播Adapter HomeBannerAdapter bannerAdapter = new HomeBannerAdapter(bannerList, activity); targetVp.setAdapter(bannerAdapter); //初始化当前位置 targetVp.setCurrentItem(bannerList.size() * 1000); //当前position selectedBanner = bannerList.size() * 1000; } /** * 通过网络Url加载轮播图 * * @param activity * @param img_urls 网络图片的URL */ public void initShowImageForNet(Activity activity, List<String> img_urls) { //标识是网络加载 isNetImg = true; //指示器布局 LinearLayout ly_indication = new LinearLayout(activity); LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); // 指示器边距 params.bottomMargin = 15; //指示器位置 params.addRule(ALIGN_PARENT_BOTTOM); params.addRule(CENTER_HORIZONTAL); //添加到View中 addView(ly_indication, params); //图片集合和指示器集合 bannerList = new ArrayList<View>(); indicationList = new ArrayList<View>(); for (int i = 0; i < img_urls.size(); i++) { //初始化图片 ImageView iv = new ImageView(activity); iv.setScaleType(ImageView.ScaleType.FIT_XY); GlideUtils.setImageView(context, img_urls.get(i), iv); bannerList.add(iv); //初始化指示器 ImageView iv2 = new ImageView(activity); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); lp.setMargins(8, 0, 0, 0); iv2.setLayoutParams(lp); if (i == 0) { iv2.setBackgroundResource(R.drawable.home_top_ic_point_on); } else { iv2.setBackgroundResource(R.drawable.home_top_ic_point_off); } indicationList.add(iv2); //添加到圆点布局 ly_indication.addView(iv2); } //初始化轮播数据 HomeBannerAdapter bannerAdapter = new HomeBannerAdapter(bannerList, activity); targetVp.setAdapter(bannerAdapter); //初始化当前位置 targetVp.setCurrentItem(bannerList.size() * 1000); //当前position selectedBanner = bannerList.size() * 1000; }
5、实现监听事件
@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { //改变当前位置指针 selectedBanner = position; //改变指示器变化 bannerPointLight(position % indicationList.size()); } @Override public void onPageScrollStateChanged(int state) { } @Override public boolean onTouch(View v, MotionEvent event) { //如果是网络加载则没必要监听 if (isNetImg) { return false; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //结束轮播 mHandler.removeCallbacksAndMessages(null); break; case MotionEvent.ACTION_UP: //开启轮播 mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000); break; case MotionEvent.ACTION_CANCEL: //开启轮播 mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000); break; } return false; }
6、提供开启轮播和结束轮播的方法
/** * 开始轮播 */ public void startBanner() { //开启轮播 mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000); } /** * 结束轮播 */ public void endBanner() { //结束轮播 mHandler.removeCallbacksAndMessages(null); }
/** * 消息处理器 */ private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case BANNER_CHANGE: //形成轮播循环 targetVp.setCurrentItem(selectedBanner + 1); mHandler.sendEmptyMessageDelayed(BANNER_CHANGE, 3000); break; } } };
/** * 适配器 */ public class HomeBannerAdapter extends PagerAdapter { private List<View> views; private Context context; public HomeBannerAdapter(List<View> views, Context context) { this.context = context; this.views = views; } public Object instantiateItem(View container, int position) { final int currentItem = position % views.size(); ((ViewPager) container).addView(views.get(currentItem)); return views.get(currentItem); } public void destroyItem(View container, int position, Object object) { ((ViewPager) container).removeView((View) object); } public int getCount() { return Integer.MAX_VALUE; } public boolean isViewFromObject(View arg0, Object arg1) { return (arg0 == arg1); } }
9、编写两个圆点的xml文件
① 红点
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#FF5000"/> <stroke android:width="0.1dp" android:color="#8888" /> <size android:width="6dp" android:height="6dp" /> </shape>
② 灰点
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#88ffffff"/> <stroke android:width="0.1dp" android:color="#8888" /> <size android:width="6dp" android:height="6dp" /> </shape>
10、接着就可以在Acitivity中使用我们的自定义的BannerView
① 编写布局文件,使用我们的自定义BannerView
<com.handsome.didi.View.MyBannerView android:id="@+id/vp_banner" android:layout_width="match_parent" android:layout_height="120dp" />
vp_banner = findView(R.id.vp_banner); vp_banner.initShowImageForNet(getActivity(), new ArrayList<String>{"","","",""});
@Override public void onResume() { super.onResume(); //开始轮播 vp_banner.startBanner(); } @Override public void onPause() { super.onPause(); //停止轮播 vp_banner.endBanner(); }
源码下载
源码下载说明
1、网络图片加载要用到第三库Glide
2、网络加载默认是不会自动轮播的,如果需要自动轮播需要将if(isNetImg){return false};去掉