您的位置:首页 > 其它

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

2016-12-06 20:07 453 查看
自定义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

c2b3
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.将mForePaint和mBgPaint抽取成员变量

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Viewpager Indicator