Android简单的ViewPager指示器

来源:互联网 发布:万能的淘宝 编辑:程序博客网 时间:2024/05/16 01:37

平常写项目在写介绍页,或者一些简单的轮播图的时候,总会需要搭配指示器来标明当前在什么位置.写法也比较多,刚好自己需要用到,以前用的一些方法,用起来需要配置好多东西,有些大材小用,所以来简单的实现一个.效果图如下:

效果图


一、简单分析与代码实现

因为比较简单,所以就简单的分析一下:
1)每一个指示器项有两种状态,普通状态和选中状态,所以需要准备两种状态的图片.
2)指示器的个数和ViewPager的页数要保持一致.可以引用ViewPager对象,来获取ViewPager的页数.从而创建指示器.
3)指示器要跟随ViewPager的移动来动态的改变状态.同样可以引用ViewPager对象,对ViewPager进行监听,处理指示器的状态改变.

有了思路,就来具体实现一下,提出一些自定义属性,在attr文件中定义:

 <?xml version="1.0" encoding="utf-8"?><resources>    <!--IndicatorView相关-->    <!--普通指示器图片-->    <attr name="normalDrawable" format="reference"/>    <!--选中指示器图片-->    <attr name="selectDrawable" format="reference"/>    <!--指示器间隔-->    <attr name="indicatorInterval" format="dimension"/>    <!--普通指示器颜色-->    <attr name="normalColor" format="color"/>    <!--选中指示器颜色-->    <attr name="selectColor" format="color"/>    <!--圆点弧度-->    <attr name="indicatorRadius" format="integer"/>    <declare-styleable name="IndicatorView">        <attr name="normalDrawable"/>        <attr name="selectDrawable"/>        <attr name="indicatorInterval"/>        <attr name="normalColor"/>        <attr name="selectColor"/>        <attr name="indicatorRadius"/>    </declare-styleable></resources>

新建一个IndicatorView继承自LinearLayout即可,因为需要对ViewPager进行监听,所以实现一下ViewPager的监听.定义变量并获取自定义属性:

/** * 轮播图圆形指示器 * Created by junweiliu on 16/6/15. */public class IndicatorView extends LinearLayout implements ViewPager.OnPageChangeListener {    /**     * 需要创建的指示器个数     */    private int childViewCount = 0;    /**     * 设置圆点间margin     */    private int mInterval;    /**     * 当前选中的位置     */    private int mCurrentPostion = 0;    /**     * 普通显示的图片     */    private Bitmap normalBp;    /**     * 选中时显示的图片     */    private Bitmap selectBp;    /**     * 设置的轮播图Vp     */    private ViewPager mViewPager;    /**     * 指示器单项宽度     */    private int mWidth;    /**     * 指示器单项高度     */    private int mHeight;    /**     * 圆点半径     */    private int mRadius;    /**     * 普通状态圆点颜色     */    private int normalColor;    /**     * 选中状态圆点颜色     */    private int selectColor;    /**     * 对外提供ViewPager的回调接口     */    interface OnPageChangeListener {        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);        public void onPageSelected(int position);        public void onPageScrollStateChanged(int state);    }    /**     * 回调接口     */    private OnPageChangeListener mListener;    /**     * 设置回调     *     * @param listener     */    public void setOnPageChangeListener(OnPageChangeListener listener) {        this.mListener = listener;    }    public IndicatorView(Context context) {        this(context, null);    }    public IndicatorView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        // 获取自定义属性        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView);        normalBp = drawableToBitamp(ta.getDrawable(R.styleable.IndicatorView_normalDrawable));        selectBp = drawableToBitamp(ta.getDrawable(R.styleable.IndicatorView_selectDrawable));        mInterval = ta.getDimensionPixelOffset(R.styleable.IndicatorView_indicatorInterval, 6);        normalColor = ta.getColor(R.styleable.IndicatorView_normalColor, Color.GRAY);        selectColor = ta.getColor(R.styleable.IndicatorView_selectColor, Color.RED);        mRadius = ta.getInteger(R.styleable.IndicatorView_indicatorRadius, 6);        ta.recycle();        // 初始化        init();    }

这里因为监听了ViewPager,所以需要对外提供回调方法,将ViewPager的监听方法暴露出去,方便其他地方对ViewPager对象进行监听.

再来看一下init方法:

    /**     * 初始化数据     */    private void init() {        // 处理自定义属性        if (null == normalBp) {            normalBp = makeIndicatorBp(normalColor);        }        if (null == selectBp) {            selectBp = makeIndicatorBp(selectColor);        }        mWidth = normalBp.getWidth();        mHeight = normalBp.getWidth();    }    /**     * 创建圆点指示器图片     *     * @param color 创建不同颜色的指示器项     * @return     */    private Bitmap makeIndicatorBp(int color) {        Bitmap normalBp = Bitmap.createBitmap(mRadius * 2, mRadius * 2,                Bitmap.Config.ARGB_8888);        Paint paint = new Paint();        paint.setAntiAlias(true);        paint.setColor(color);        Canvas canvas = new Canvas(normalBp);        canvas.drawCircle(mRadius, mRadius, mRadius, paint);        return normalBp;    }

在init方法中对自定义属性做了相关处理,如果没有设置指示器的图片,就建立两种状态下的圆形指示器图片.

接着看一下对于ViewPager对象的引用及处理:

    /**     * 设置Vp     *     * @param viewpager     */    public void setViewPager(ViewPager viewpager) {        if (null == viewpager) {            return;        }        if (null == viewpager.getAdapter()) {            throw new IllegalStateException("ViewPager does not have adapter.");        }        this.mViewPager = viewpager;        this.mViewPager.addOnPageChangeListener(this);        this.childViewCount = viewpager.getAdapter().getCount();        invalidate();    }    /**     * 设置Vp     *     * @param viewpager     * @param currposition 当前选中的位置     */    public void setViewPager(ViewPager viewpager, int currposition) {        if (null == viewpager) {            return;        }        if (null == viewpager.getAdapter()) {            throw new IllegalStateException("ViewPager does not have adapter.");        }        this.mViewPager = viewpager;        this.mViewPager.addOnPageChangeListener(this);        this.childViewCount = viewpager.getAdapter().getCount();        this.mCurrentPostion = currposition;        invalidate();    }        @Override    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {        if (null != mListener) {            mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);        }    }    @Override    public void onPageSelected(int position) {        setIndicatorState(position);        if (null != mListener) {            mListener.onPageSelected(position);        }    }    @Override    public void onPageScrollStateChanged(int state) {        if (null != mListener) {            mListener.onPageScrollStateChanged(state);        }    }    /**     * 设置指示器的状态     *     * @param position     */    public void setIndicatorState(int position) {        for (int i = 0; i < getChildCount(); i++) {            if (i == position)                ((ImageView) getChildAt(i)).setImageBitmap(selectBp);            else                ((ImageView) getChildAt(i)).setImageBitmap(normalBp);        }    }

获取ViewPager对象,并通过对ViewPager对象的监听去设置指示器的状态.获取ViewPager对象提供两种方法,方便设置指示器默认显示的位置.

最后看一下指示器的创建:

    /**     * 重绘     *     * @param canvas     */    @Override    protected void dispatchDraw(Canvas canvas) {        // 创建指示器圆点        if (getChildCount() < childViewCount && getChildCount() == 0) {            for (int i = 0; i < childViewCount; i++) {                addView(makeIndicatorItem());            }            // 设置默认选中指示器            setIndicatorState(mCurrentPostion);        }        super.dispatchDraw(canvas);    }    /**     * 创建指示器     *     * @return     */    private View makeIndicatorItem() {        ImageView iv = new ImageView(getContext());        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);        lp.width = normalBp.getWidth();        lp.height = normalBp.getHeight();        lp.rightMargin = mInterval;        iv.setImageBitmap(normalBp);        iv.setLayoutParams(lp);        return iv;    }

在绘制过程中,去创建指示器,并设置相关属性和默认选中指示器的位置.


二、完整代码及使用

不是特别复杂,注释也比较全,看一下完整代码:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:idv="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="225dp"    tools:context="com.example.junweiliu.simpleindicatorview.MainActivity">    <!--轮播图-->    <android.support.v4.view.ViewPager        android:id="@+id/vp_banner"        android:layout_width="match_parent"        android:layout_height="225dp"        >    </android.support.v4.view.ViewPager>    <!--指示器-->    <com.example.junweiliu.simpleindicatorview.IndicatorView        android:id="@+id/idv_banner"        android:layout_width="match_parent"        android:layout_height="10dp"        android:layout_alignParentBottom="true"        android:layout_marginTop="20dp"        idv:indicatorInterval="10dp"        android:gravity="center_horizontal"        idv:normalDrawable="@mipmap/oval_indicator_grey"        idv:selectDrawable="@mipmap/oval_indicator_green">    </com.example.junweiliu.simpleindicatorview.IndicatorView></RelativeLayout>

banner_item.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="match_parent"              android:orientation="vertical">    <ImageView        android:id="@+id/iv_banner_item"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:scaleType="fitXY"        /></LinearLayout>

IndicatorView:

package com.example.junweiliu.simpleindicatorview;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.View;import android.widget.ImageView;import android.widget.LinearLayout;/** * 轮播图圆形指示器 * Created by junweiliu on 16/6/15. */public class IndicatorView extends LinearLayout implements ViewPager.OnPageChangeListener {    /**     * 需要创建的指示器个数     */    private int childViewCount = 0;    /**     * 设置圆点间margin     */    private int mInterval;    /**     * 当前选中的位置     */    private int mCurrentPostion = 0;    /**     * 普通显示的图片     */    private Bitmap normalBp;    /**     * 选中时显示的图片     */    private Bitmap selectBp;    /**     * 设置的轮播图Vp     */    private ViewPager mViewPager;    /**     * 指示器单项宽度     */    private int mWidth;    /**     * 指示器单项高度     */    private int mHeight;    /**     * 圆点半径     */    private int mRadius;    /**     * 普通状态圆点颜色     */    private int normalColor;    /**     * 选中状态圆点颜色     */    private int selectColor;    /**     * 对外提供ViewPager的回调接口     */    interface OnPageChangeListener {        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);        public void onPageSelected(int position);        public void onPageScrollStateChanged(int state);    }    /**     * 回调接口     */    private OnPageChangeListener mListener;    /**     * 设置回调     *     * @param listener     */    public void setOnPageChangeListener(OnPageChangeListener listener) {        this.mListener = listener;    }    public IndicatorView(Context context) {        this(context, null);    }    public IndicatorView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        // 获取自定义属性        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView);        normalBp = drawableToBitamp(ta.getDrawable(R.styleable.IndicatorView_normalDrawable));        selectBp = drawableToBitamp(ta.getDrawable(R.styleable.IndicatorView_selectDrawable));        mInterval = ta.getDimensionPixelOffset(R.styleable.IndicatorView_indicatorInterval, 6);        normalColor = ta.getColor(R.styleable.IndicatorView_normalColor, Color.GRAY);        selectColor = ta.getColor(R.styleable.IndicatorView_selectColor, Color.RED);        mRadius = ta.getInteger(R.styleable.IndicatorView_indicatorRadius, 6);        ta.recycle();        // 初始化        init();    }    /**     * 初始化数据     */    private void init() {        // 处理自定义属性        if (null == normalBp) {            normalBp = makeIndicatorBp(normalColor);        }        if (null == selectBp) {            selectBp = makeIndicatorBp(selectColor);        }        mWidth = normalBp.getWidth();        mHeight = normalBp.getWidth();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);        // 如果是wrap_content设置为图片宽高,否则设置为父容器宽高        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : (mWidth + mInterval) * childViewCount                , (heightMode == MeasureSpec.EXACTLY) ? sizeHeight                        : mHeight);    }    /**     * 重绘     *     * @param canvas     */    @Override    protected void dispatchDraw(Canvas canvas) {        // 创建指示器圆点        if (getChildCount() < childViewCount && getChildCount() == 0) {            for (int i = 0; i < childViewCount; i++) {                addView(makeIndicatorItem());            }            // 设置默认选中指示器            setIndicatorState(mCurrentPostion);        }        super.dispatchDraw(canvas);    }    /**     * 设置Vp     *     * @param viewpager     */    public void setViewPager(ViewPager viewpager) {        if (null == viewpager) {            return;        }        if (null == viewpager.getAdapter()) {            throw new IllegalStateException("ViewPager does not have adapter.");        }        this.mViewPager = viewpager;        this.mViewPager.addOnPageChangeListener(this);        this.childViewCount = viewpager.getAdapter().getCount();        invalidate();    }    /**     * 设置Vp     *     * @param viewpager     * @param currposition 当前选中的位置     */    public void setViewPager(ViewPager viewpager, int currposition) {        if (null == viewpager) {            return;        }        if (null == viewpager.getAdapter()) {            throw new IllegalStateException("ViewPager does not have adapter.");        }        this.mViewPager = viewpager;        this.mViewPager.addOnPageChangeListener(this);        this.childViewCount = viewpager.getAdapter().getCount();        this.mCurrentPostion = currposition;        invalidate();    }    /**     * 创建指示器     *     * @return     */    private View makeIndicatorItem() {        ImageView iv = new ImageView(getContext());        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);        lp.width = normalBp.getWidth();        lp.height = normalBp.getHeight();        lp.rightMargin = mInterval;        iv.setImageBitmap(normalBp);        iv.setLayoutParams(lp);        return iv;    }    /**     * 创建圆点指示器图片     *     * @param color 创建不同颜色的指示器项     * @return     */    private Bitmap makeIndicatorBp(int color) {        Bitmap normalBp = Bitmap.createBitmap(mRadius * 2, mRadius * 2,                Bitmap.Config.ARGB_8888);        Paint paint = new Paint();        paint.setAntiAlias(true);        paint.setColor(color);        Canvas canvas = new Canvas(normalBp);        canvas.drawCircle(mRadius, mRadius, mRadius, paint);        return normalBp;    }    /**     * drawable转bitmap     *     * @param drawable     * @return     */    private Bitmap drawableToBitamp(Drawable drawable) {        if (null == drawable) {            return null;        }        if (drawable instanceof BitmapDrawable) {            BitmapDrawable bd = (BitmapDrawable) drawable;            return bd.getBitmap();        }        int w = drawable.getIntrinsicWidth();        int h = drawable.getIntrinsicHeight();        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bitmap);        drawable.setBounds(0, 0, w, h);        drawable.draw(canvas);        return bitmap;    }    @Override    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {        if (null != mListener) {            mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);        }    }    @Override    public void onPageSelected(int position) {        setIndicatorState(position);        if (null != mListener) {            mListener.onPageSelected(position);        }    }    @Override    public void onPageScrollStateChanged(int state) {        if (null != mListener) {            mListener.onPageScrollStateChanged(state);        }    }    /**     * 设置指示器的状态     *     * @param position     */    public void setIndicatorState(int position) {        for (int i = 0; i < getChildCount(); i++) {            if (i == position)                ((ImageView) getChildAt(i)).setImageBitmap(selectBp);            else                ((ImageView) getChildAt(i)).setImageBitmap(normalBp);        }    }}

BannerPagerAdapter:

package com.example.junweiliu.simpleindicatorview;import android.content.Context;import android.support.v4.view.PagerAdapter;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import java.util.ArrayList;import java.util.List;/** * Created by junweiliu on 16/6/14. * VP适配器 */public class BannerPagerAdapter extends PagerAdapter {    /**     * 上下文     */    private Context mContext;    /**     * 图像列表     */    private List<Integer> pictureList = new ArrayList<>();    public BannerPagerAdapter(Context context, List<Integer> pictureList) {        this.mContext = context;        this.pictureList = pictureList;    }    @Override    public int getCount() {        return pictureList.size();    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view == object;    }    @Override    public Object instantiateItem(ViewGroup container, final int position) {        View view = LayoutInflater.from(mContext).inflate(R.layout.banner_item, container, false);        ImageView imageView = (ImageView) view.findViewById(R.id.iv_banner_item);        imageView.setImageResource(pictureList.get(position));        container.addView(view);        return view;    }    @Override    public void finishUpdate(ViewGroup container) {    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView((View) object);    }}

MainActivity:

package com.example.junweiliu.simpleindicatorview;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    /**     * 轮播图     */    private ViewPager mViewPager;    /**     * 指示器     */    private IndicatorView mIndicatorView;    /**     * 适配器     */    private BannerPagerAdapter mBannerPagerAdapter;    private List<Integer> pictureList = new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initDatas();        initView();    }    /**     * 初始化数据     */    private void initDatas() {        pictureList.add(R.drawable.pic_one);        pictureList.add(R.drawable.pic_two);        pictureList.add(R.drawable.pic_three);        pictureList.add(R.drawable.pic_one);        pictureList.add(R.drawable.pic_two);        pictureList.add(R.drawable.pic_three);    }    /**     * 初始化控件     */    private void initView() {        mViewPager = (ViewPager) findViewById(R.id.vp_banner);        mIndicatorView = (IndicatorView) findViewById(R.id.idv_banner);        mBannerPagerAdapter = new BannerPagerAdapter(this, pictureList);        mViewPager.setAdapter(mBannerPagerAdapter);        mIndicatorView.setViewPager(mViewPager);        mIndicatorView.setOnPageChangeListener(new IndicatorView.OnPageChangeListener() {            @Override            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            }            @Override            public void onPageSelected(int position) {            }            @Override            public void onPageScrollStateChanged(int state) {            }        });    }}

关于无限循环和自动播放的内容可以参考

无限循环和自动播放的实现

4 1