ViewPager是android中的常见控件,今天就写一个ViewPager的常见用法,自定义轮播图,可无限轮播,可点击跳转可以动态添加指示点,且指示点不会乱跳。

下面是效果图

首先写一个java类,继承ViewPager:

package com.example.administrator.mybanner;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;/**
  * Created by bean on 2016/12/9.
  */
 public class CycleViewPager extends ViewPager {
     private OnItemClickListener mOnItemClickListener;
     private int mDownX;
     private int mDownY;
     private int mDownTime;
     public CycleViewPager(Context context) {
         super(context);
     }
     public CycleViewPager(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
     @Override
     public void setOnPageChangeListener(OnPageChangeListener listener) {
         MyPageChangeListener myPageChangeListener = new MyPageChangeListener(listener);
         super.setOnPageChangeListener(myPageChangeListener);
     }
     @Override
     public void setAdapter(PagerAdapter adapter) {
         //  修正  adapter 中position
         MyAdapter myAdapter = new MyAdapter(adapter);
         setOnPageChangeListener(null); //手动增加一个监听
         super.setAdapter(myAdapter);
         setCurrentItem(1);
         //开启自动轮播
         startScroll();//自动轮播
     }
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         //手指触摸  按下 停止轮播  抬起继续轮播
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 //记录按下时候手指的坐标
                 mDownX = (int) ev.getX();
                 mDownY = (int) ev.getY();
                 mDownTime = (int) System.currentTimeMillis();
                 stopScroll();
                 break;
             case MotionEvent.ACTION_MOVE:
                 break;
             case MotionEvent.ACTION_UP:
                 startScroll();//当手指抬起的时候开启自动轮播
                 int upX = (int) ev.getX();
                 int upY = (int) ev.getY();
                 int upTime = (int) System.currentTimeMillis();
                 int disX = Math.abs(upX- mDownX);
                 int disY = Math.abs(upY - mDownY);
                 //判断手指在屏幕上移动的距离和时间,如果时间在500毫秒之内,且移动的距离小于5就说明是单击事件
                 if (disX<=5&&disY<=5&&upTime - mDownTime<=500){
                     //如果传进来的条目点击事件不为空,就执行条目点击事件
                     if (mOnItemClickListener !=null){
                         mOnItemClickListener.onItemClick(getCurrentItem());
                     }
                 }
                 break;
             case MotionEvent.ACTION_CANCEL:
                 //取消事件,当手指移出轮播图的区域后,开启轮播
                 startScroll();
                 break;
         }
         return super.onTouchEvent(ev);
     }
     Handler handler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             super.handleMessage(msg);
             switch (msg.what){
                 case 1:
                     int currentItem = getCurrentItem();
                     currentItem++;
                     setCurrentItem(currentItem);
                     handler.sendEmptyMessageDelayed(1, 2000);//4s发送消息
                     break;
                 default:
                     break;
             }
         }
     };
     public void startScroll() {
         //开启轮播之前先关闭轮播,以免混乱
         stopScroll();
         //开启轮播
         handler.sendEmptyMessageDelayed(1, 2000);//2s发送消息
     }
     public void stopScroll()
     {
         //关闭轮播,删除所有的handler消息
         handler.removeMessages(1);
     }
     public class MyPageChangeListener implements OnPageChangeListener {
         private OnPageChangeListener listener;
         private int position;
         public MyPageChangeListener(OnPageChangeListener listener) {
             this.listener = listener;
         }
         @Override
         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
             if (listener != null)
                 listener.onPageScrolled(position, positionOffset, positionOffsetPixels);
         }
         @Override
         public void onPageSelected(int position) {
             this.position = position;
             if (listener != null)
                 listener.onPageSelected(position);
         }
         @Override
         public void onPageScrollStateChanged(int state) {
             //状态改变的时候 调用    手指抬起的时候切换
             if (state == ViewPager.SCROLL_STATE_IDLE) {
                 //空闲切换
                 // 页面切换   自动的切换到对应的界面    最后一个A----->第一个A
                 if (position == getAdapter().getCount() - 1) {
                     //最后一个元素  是否平滑切换
                     setCurrentItem(1, false);
                 } else if (position == 0) {
                     //是第一个元素{D] ----> 倒数第二个元素[D]
                     setCurrentItem(getAdapter().getCount() - 2, false);
                 }
             }
             if (listener != null)
                 listener.onPageScrollStateChanged(state);
         }
     }
     public void setOnItemClickListener(OnItemClickListener listener) {
         this.mOnItemClickListener = listener;
     }
     /**
      * 轮播图页面的点击事件
      */
     public interface OnItemClickListener {
         void onItemClick(int position);
     }
     public class MyAdapter extends PagerAdapter {
         private PagerAdapter adapter;
         public MyAdapter(PagerAdapter adapter) {
             this.adapter = adapter;  //[ABCD]
         }
         @Override
         public Object instantiateItem(ViewGroup Container, int position) {
             //  position 已经是 [DABCDA] 的索引了
             // 修正后的索引 应该是 [ABCD]的索引
             //修正position
             if (position == 0) { //新增的D
                 position = adapter.getCount() - 1;// 最后一个元素
             } else if (position == getCount() - 1) {  //最后一个元素 A
                 position = 0;
             } else {
                 position -= 1; //计算新的索引
             }
             return adapter.instantiateItem(Container, position);
         }
         @Override
         public void destroyItem(ViewGroup container, int position, Object object) {
             adapter.destroyItem(container, position, object);
         }
         @Override
         public int getCount() {
             return adapter.getCount() + 2;
         }
         @Override
         public boolean isViewFromObject(View view, Object object) {
             return adapter.isViewFromObject(view, object);
         }
     }
 }

接着就是用法了,我们可以在布局中加入我们的轮播图布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 

     xmlns:tools="http://schemas.android.com/tools" 

     android:layout_width="match_parent" 

     android:layout_height="200dp" 

     tools:context=".MainActivity"> 

     <com.example.administrator.mybanner.CycleViewPager 

         android:id="@+id/banner" 

         android:layout_width="match_parent" 

         android:layout_height="200dp" /> 

     <LinearLayout 

         android:id="@+id/ll_points" 

         android:gravity="center_horizontal" 

         android:layout_width="match_parent" 

         android:layout_height="wrap_content" 

         android:layout_alignParentBottom="true" 

         android:orientation="horizontal"></LinearLayout> 

</RelativeLayout>

在activity中设置开启关闭轮播图,添加指示点:

package com.example.administrator.mybanner; 

import android.app.Activity;
 import android.content.Context; 

 import android.os.Bundle; 

 import android.support.v4.view.ViewPager; 

 import android.util.Log; 

 import android.widget.ImageView; 

 import android.widget.LinearLayout; 

 import android.widget.Toast; 

 import java.util.ArrayList; 

 import java.util.List; 

 public class MainActivity extends Activity { 

     private CycleViewPager pager; 

     private List<Integer> list = new ArrayList<>(); 

     private LinearLayout ll_point; 

     private List<ImageView> list1; 

     private Context _context; 

     @Override 

     protected void onCreate(Bundle savedInstanceState) { 

         super.onCreate(savedInstanceState); 

         setContentView(R.layout.activity_main); 

         this._context = this; 

         initView(); 

         initData(); 

         initListener(); 

     } 

     protected void initView() { 

 //找到我们的ViewPager和指示点的容器 

         pager = (CycleViewPager) findViewById(R.id.banner); 

         ll_point = (LinearLayout) findViewById(R.id.ll_points); 

     } 

     @Override 

     public void onStart() { 

         super.onStart(); 

 //当activity可见的时候开启轮播图 

         addPoint(); 

         pager.startScroll(); 

     } 

     @Override 

     public void onStop() { 

         super.onStop(); 

 //不可见的时候关闭轮播图 

         pager.stopScroll(); 

     } 

     protected void initData() { 

 //初始化轮播图数据 

         if (list.size() == 0) { 

             list.add(R.drawable.picture1); 

             list.add(R.drawable.picture2); 

             list.add(R.drawable.picture3); 

             list.add(R.drawable.picture4); 

         } 

         addPoint(); 

         pager.setAdapter(new MyItemPagerAdapter(_context, list)); 

         pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { 

             @Override 

             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

             } 

             @Override 

             public void onPageSelected(int position) { 

                 Log.i("页面改变了", position + ""); 

                 //当页面改变的时候,改变圆点的样式 

                 for (int i = 0; i < list1.size(); i++) { 

                     if (i == position - 1) { 

                         list1.get(i).setImageResource(R.drawable.selected_point); 

                     } else { 

                         list1.get(i).setImageResource(R.drawable.default_point); 

                     } 

                 } 

             } 

             @Override 

             public void onPageScrollStateChanged(int state) { 

             } 

         }); 

     } 

     private void addPoint() { 

         //存放imageView 

         list1 = new ArrayList(); 

         list1.clear(); 

         ll_point.removeAllViews(); 

         for (int i = 0; i < list.size(); i++) { 

 //遍历所有的指示点,设置当前被选中的页面的指示点为黑色,其他的为白色 

             ImageView imageView = new ImageView(_context); 

             if (i == 0) { 

                 imageView.setImageResource(R.drawable.selected_point); 

             } else { 

                 imageView.setImageResource(R.drawable.default_point); 

             } 

             //给指示点添加一个间隔 

             LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); 

             params.leftMargin = 10; 

             list1.add(imageView); 

             ll_point.addView(imageView, params); 

         } 

    }
  protected void initListener() {
         pager.setOnItemClickListener(new CycleViewPager.OnItemClickListener() { 

             @Override 

             public void onItemClick(int position) { 

                 //可以在这里做跳转的操作,当轮播图页面被点击的时候,就会响应 

                 Toast.makeText(_context, "跳转到详情界面", Toast.LENGTH_SHORT).show(); 

             } 

         }); 

     } 

 }

ViewPager的适配器类:

package com.example.administrator.mybanner;


 import android.content.Context;
 import android.support.v4.view.PagerAdapter;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import com.bumptech.glide.Glide;
 import java.util.ArrayList;
 import java.util.List;
 /**
  * Created by Administrator on 2016/11/3.
  */
 public class MyItemPagerAdapter extends PagerAdapter {
     private List<Integer> list = new ArrayList<>();
     private Context _context;
     public MyItemPagerAdapter(Context context ,List<Integer> list) {
         this.list = list;
         this._context = context;
     }
     @Override
     public int getCount() {
         return list.size();
     }
     @Override
     public boolean isViewFromObject(View view, Object o) {
         return view == o;
     }
     @Override
     public Object instantiateItem(ViewGroup container, int position) {
         ImageView view =new ImageView(_context);
         view.setScaleType(ImageView.ScaleType.FIT_XY);


         Glide.with(_context).load(list.get(position)).into(view);
         container.addView(view);
         return view;
     }
     @Override
     public void destroyItem(ViewGroup container, int position, Object object) {
         container.removeView((View) object);
     }
 }//指示点的两种状态,这里是用shape画出来的:下面是默认状态
<?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
 <corners android:radius="@dimen/app_margin_0" />
     <gradient android:startColor="@color/white" android:endColor="@color/white"/>
     <size android:height="@dimen/point_size" android:width="@dimen/point_size"/>
 </shape>

下面是页面被选中的时候的状态:

<?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
 <corners android:radius="@dimen/app_margin_0" />
     <gradient android:startColor="@color/black" android:endColor="@color/black"/>
     <size android:height="@dimen/point_size" android:width="@dimen/point_size"/>
 </shape>

下面的四张图是代码中的示例图片:

好了,轮播图这就完成了。