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) { } }); }}
关于无限循环和自动播放的内容可以参考
无限循环和自动播放的实现
- Android简单的ViewPager指示器
- Android简单的ViewPager指示器
- 简单实用的ViewPager指示器NavigationTabStrip
- android 中 viewpager 滑动的指示器
- android 中 viewpager 滑动的指示器
- Android 自制ViewPager的指示器PagerIndicator
- Android自定义View--Flyme6的Viewpager指示器
- Android ViewPager指示器 IndicatorBar
- Android自定义ViewPager指示器
- Android ViewPager指示器 IndicatorBar
- Android-自定义ViewPager指示器
- Android自定义ViewPager指示器
- Android 实现Viewpager指示器
- android ViewPager 指示器 PageIndicator
- 设计ViewPager的指示器
- ViewPager页面指示器简单实现
- 关于ViewPager当前页卡指示器的简单实现方法
- Android Viewpager界面指示器案例
- Android App 启动页(Splash)黑/白闪屏现象产生原因与解决办法
- LeetCode:Maximal Rectangle
- 【leetcode】155. Min Stack【E】【98】
- Not a host:port pair: PBUF(用Java客户端(Eclipse平台)连接Hbase)&&apache官网Jar下载流程
- addEventListener
- Android简单的ViewPager指示器
- Spring 集成CXF框架发布Webservice服务 和 使用jdk生成Webservice clinet
- Android 踩坑记(一) title 渐变效果
- 初识JNI
- Javascript的匿名函数与自执行
- MAC OSX学习(一)
- n个元素的全排列(递归+去重)
- jquery同一页面跳转到指定位置
- 3G 模块驱动应用开发总结