使用Viewpager Indicator实现图片无限轮播

来源:互联网 发布:linux vi 保存退出 编辑:程序博客网 时间:2024/05/16 06:41

自定义Indicator控件设置XML属性介绍:

Android Viewpager Indicator是Android开发中最常用的控件之一,几乎所有的新闻类APP中都有使用,下面介绍其基本使用方法。

1. 首先一个indicator必须要与一个ViewPager关联在一起,所以它提供了一个setViewPager方法。
2 .它扩展了ViewPager.OnPageChangeListener接口,表示接管了ViewPager的Pager改变时的监听处理,这也是为什么为ViewPager设置OnPageChangeListener监听器时不能设置在ViewPager上而必须设置在indicator上的原因。   

                             

            最终实现效果:

                                                                      

Java代码:

实现步骤:

首先我们创建一个集合,为了装ViewPager加载的图片控件,在定义一个Indicator的成员变量.

创建一个Handler设置为全局,通过Handler实现图片无限轮播,下面我会给大家详细的说明图片无限轮播的实现方法

 //创建一个集合装Viewpager加载的图片控件    private List<View> mViews = new ArrayList<View>();    private Indicator mIn;    private Handler mHandler = new Handler();    private ViewPager mViewPager;
然后在onCreate()里实现:

  @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化viewpager的item数据,往集合里面放数据,方便ViewPager拿数据        initData();        //初始化控件        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);        //初始化我的自定义控件        mIn = (Indicator) findViewById(R.id.indicator);        //设置ViewPager的监听器        viewPager.setOnPageChangeListener(new MyPagerListner());        //设置ViewPager适配器        viewPager.setAdapter(new MyPagerAdapter());    }
然后初始化ViewPager的item数据,最后别忘记调用initData方法
    private void initData() {        for (int x = 0; x < 4; x++) {            //通过布局填充器,把一个布局XML文件转换为View对象            View inflate = getLayoutInflater().inflate(R.layout.pager_item, null);            //找到布局View里的ImageView控件对象            ImageView imageview = (ImageView) inflate.findViewById(R.id.iv);            //往ImageView控件里放图片            imageview.setImageResource(R.mipmap.ic_launcher);            //最后把布局View控件放到集合里            mViews.add(inflate);        }    }

创建ViewPager适配器,重写4个方法,下面给大家介绍这4个方法的作用.

 1:getCount()是设置ViewPager的item数量

 2:isViewFromObject()固定的格式

 3:destroyItem()防止内存溢出,溢出ImageView对象

 4:instantiateItem()此方法类似于ListView中的getView,第一个参数是ViewPager的化身,第二个参数是item的位置

 class MyPagerAdapter extends PagerAdapter {               @Override        public int getCount() {            return Integer.MAX_VALUE;        }                @Override        public boolean isViewFromObject(View view, Object object) {            return view == object;        }               @Override        public void destroyItem(ViewGroup container, int position, Object object) {            position %= 4;//防止角标越界            container.removeView(mViews.get(position));        }               @Override        public Object instantiateItem(ViewGroup container, int position) {            position %= 4;//防止角标越界            //从集合里拿对应位置的图片            View view = mViews.get(position);            //把ImageView的对象添加到Viewpager            container.addView(view);            //返回View对象            return view;        }    }
创建ViewPager的监听事件:

1:onPageScrolled()是滑动时调用

2:onPageScrollStateChanged()是选中时调用

3:onPageScrollStateChanged()是滑动状态改变时回调的方法

  class MyPagerListner implements ViewPager.OnPageChangeListener {        /**         * @param position             item位置         * @param positionOffset       //偏移的百分比这个百分比永远接近于1         * @param positionOffsetPixels //偏移量         */        @Override        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            Log.d("DS", "onPageScrolled回调");            Log.i("ds", "position :" + position + "  positionOffset :" + positionOffset + "  positionOffsetPixels : " + positionOffsetPixels);            //往自定义控件里放入item位置及偏移的百分比,是小点可以动态的跟着ViewPager滑动            mIn.setoffest(position, positionOffset);        }        @Override        public void onPageSelected(int position) {            Log.d("DS", "onPageScrolled    回调");        }        @Override        public void onPageScrollStateChanged(int state) {            Log.d("DS", "onPageScrollStateChanged     回调    hhh");        }    }
在这里给大家呈现关于实现ViewPager图片自动轮播

 private void autoScroll() {        mHandler.postDelayed(new Runnable() {            @Override            public void run() {                //获取当前的轮播的位置                int currentItem = mViewPager.getCurrentItem();                //从当前的图切换到另一张通过(currentItem + 1)就可以实现                mViewPager.setCurrentItem(currentItem + 1);                //通过mHandler请求延迟2秒                mHandler.postDelayed(this, 2000);                //调用触摸滑动事件方法                onTouch();            }        }, 2000);    }
关于实现触摸滑动的监听事件,它的作用是当你用手触摸ViewPager时它会监听你的手势,当你触碰到时就暂停轮播.

private void onTouch() {        //通过mViewPager去设置触摸滑动的点击事件        mViewPager.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View view, MotionEvent event) {                switch (event.getAction()) {                    case MotionEvent.ACTION_MOVE:                        mHandler.removeMessages(0);                    //移除回调函数和消息                    case MotionEvent.ACTION_DOWN:                        mHandler.removeCallbacksAndMessages(null);                        break;                    //当你触摸时停止自动滑动                    case MotionEvent.ACTION_UP:                        autoScroll();                        break;                }                return false;            }        });    }}
Java布局:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.android.indicatorapp.MainActivity">    <android.support.v4.view.ViewPager        android:id="@+id/viewpager"        android:layout_width="match_parent"        android:layout_height="200dp">    </android.support.v4.view.ViewPager>    <!--使用的自定义控件-->    <!--setNumber 我们自己设置的属性,决定空心圆的多少,一开始不要加上-->    <com.example.liuy.indicatorapp.Indicator        app:setNumber="6"        android:id="@+id/indicator"        android:layout_width="200dp"        android:layout_height="60dp"        android:layout_alignBottom="@+id/viewpager"        android:layout_centerHorizontal="true"/></RelativeLayout>

接下我们创建一个Indicator这个类的实现以下步骤:

1.首先继承View,复写构造方法

public class Indicator extends View {    //实心圆的画笔;    private Paint mForePaint;    //空心圆的画笔;    private Paint mBgPaint;    //规定圆的数量,默认是4个,如果有XML指定的数量,使用指定的    private int mNumber = 4;    //圆的半径,规定默认值为10,如果有XML指定的数量,使用指定的    private int mRadius = 10;    //定义圆(空心圆)的背景颜色,默认红色,如果有XML指定的数量,使用指定的    private int mBgColor = Color.RED;    //定义圆(实心圆)的背景颜色,默认蓝色,如果有XML指定的数量,使用指定的    private int mkForeColor = Color.BLUE;
2.初始化画笔,该方法在Java代码添加控件时回调

   public Indicator(Context context, AttributeSet attrs) {        super(context, attrs);        //初始化画笔对象        initPaint();        //引用atts文件下,给自己定义控件设置属性,得到TypdeArray对象.        //参数1:attrs固定    参数2:在values文件下XML里R.styleable.下写的name名字        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Indicator);        //使用typedArray对象,把在自定义控件设置的属性和XML文件里的属性进行关联,才算完成        //参数1:R.styleable.Indicator 你在attrs定义的名字   参数2:你要管理的成员变量名(最后=也是成员变量名)        //注意你在XML文件里设置的类型属性获取时也要是对应的类型.(最后同步Gradle文件,否则在XML布局文件里依然没有办法引用)        mNumber = typedArray.getInteger(R.styleable.Indicator_setNumber, mNumber);        mRadius = typedArray.getInteger(R.styleable.Indicator_setRadius, mRadius);    }
3.复写onMeasure,方法里调用initPaint()方法

 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        initPaint();    }
4.将mForePaintmBgPaint抽取成员变量

initPaint此代码是实现画圆:

 //初始化画笔对象    private void initPaint() {        //创建画笔的对象        mForePaint = new Paint();        //设置抗锯齿(如果不设置抗锯齿画出来的图会模糊)        mForePaint.setAntiAlias(true);        //设置画笔的样式,为实心        mForePaint.setStyle(Paint.Style.FILL);        //设置画笔的颜色        mForePaint.setColor(mkForeColor);        //设置画笔的宽度        mForePaint.setStrokeWidth(2);        //创建画笔的对象,用于画空心圆        mBgPaint = new Paint();        mBgPaint.setAntiAlias(true);        mBgPaint.setStyle(Paint.Style.STROKE);        mBgPaint.setColor(mBgColor);        mBgPaint.setStrokeWidth(2);    }
5.重写onDraw方法.参数就是canvas画板,直接使用,画两种类型的圆

    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //画多个空心圆,为了使圆不重叠,所以对X轴坐标进行动态的修改        for (int i = 0; i < mNumber; i++) {            //            canvas.drawCircle(230 + i * mRadius * 3, 20, mRadius, mBgPaint);        }        //画实心圆,为使实心圆能够进行X轴移动   参数1加上了偏移量        canvas.drawCircle(230 + moffest, 20, mRadius, mForePaint);    }
6.接受外界ViewPager的Item位置,及偏移的百分比转换为偏移量:

 private float moffest;    public void setoffest(int position, float positionOffset) {        invalidate();        //为了防止角标越界,取余数        position %= mNumber;        //给成员变量设置偏移量具体数据        //因为从一个圆到另一个圆,要经过3个半径+偏移量*3个半径,也可以看出点的移动过程        moffest = position * 3 * mRadius + positionOffset * 3 * mRadius;        if (position == mNumber - 1) {            moffest = position * 3 * mRadius;        }        //关键的一点,从新绘制自定义View的方法,十分常用.(不绘制看不成自定义控件的动态效果)        invalidate();    }}


7.同步Gradle文件,否则在XML布局文件里依然没有办法引用


8.在values下创建一XML资源文件



9.在XML文件里,定义标头和属性

<?xml version="1.0" encoding="utf-8"?><resources>    <!--指定这些属性都是谁的的,注意这里添加完属性要在自己定义View类构造方法里应用-->    <!--注意:写完这个属性后,布局XML文件要想应用的话,必须要同步Gradle文件-->    <declare-styleable name="Indicator">        <!--定义控件显示圆的数量  参数format是类型-->        <attr name="setNumber" format="integer"></attr>        <!--定义控件显示圆的半径  参数format是类型-->        <attr name="setRadius" format="integer"></attr>    </declare-styleable></resources>








1 0
原创粉丝点击