无限自动循环viewpager是广告栏常见的形式,我们通常使用的viewpager没有办法实现无限循环
在以前的文章中,我介绍过如何实现无限循环的跑马灯效果教你自定义竖直跑马灯效果(广告专用)
另外,我还介绍过indicator和viewpager的结合使用,使用indicator来提示当前页面位置教你轻松自定义ViewPagerIndicator
根据上面两篇文章的原理,我们可以自定义出无限自动循环viewpager
如果大家感兴趣,可以在这篇文章之前,先看前面两篇文章
言归正传,我们整理一下实现的思路。
首先是无限循环,对于viewpager,实现的原理和跑马灯一样,例如我们要实现{1,2,3,4,5}的循环,我就在头部和尾部分别加上5,1
让viewpager翻页,我们可以使用setCurrentItem(int index)这个方法,注意这个方法带有动画效果
那么数组就变成{5,1,2,3,4,5,1},每次当循环到边界,例如5->1,当滑动动画完成以后,我们调用setCurrentItem(1,false),使其马上回到数组中,第一个1的位置
和上面带有动画效果不同,如果setCurrentItem()方法第二个参数传入false,就会瞬间跳转
这样就造成了循环的假象
然后是自动循环,这个我们在前面的文章也说过,使用hadnler自己给自己发消息的方式,在接收到消息的handleMessage()方法里面,sendMessage()就可以实现自动循环
在看代码之前,我们来看看效果图:
怎么使用这个控件呢?在布局文件里面添加
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="300dp"/>
<com.example.kaiyicky.myapplication.CircleIndicator
android:layout_centerHorizontal="true"
android:layout_marginTop="400dp"
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
在activity里面,我们要关联circleIndicator和viewpager
public class MainActivity extends FragmentActivity {
String[] CONTENT = new String[]{"3","1","2","3","1"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final android.support.v4.view.ViewPager pager = (android.support.v4.view.ViewPager)findViewById(R.id.pager);
PagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()){
@Override
public int getCount() {
return CONTENT.length;
}
@Override
public Fragment getItem(int position) {
return TestFragment.newInstance(CONTENT[position%CONTENT.length]);
}
};
pager.setAdapter(adapter);//必须在关联和startAutoScroll()前面调用
CircleIndicator circleIndicator = (CircleIndicator) findViewById(R.id.indicator);
circleIndicator.setViewPager(pager);//关联
circleIndicator.startAutoScroll();//开启自动无限循环
}
}
使用方式就是这么简单
OK,我们上代码!
对于CircleIndicator,首先是setViewpager()方法
/**
* 设置viewPager和初始位置,必须主动调用
* @param viewPager
* @param initPos
*/
public void setViewPager(ViewPager viewPager,int initPos){
if (mViewPager == viewPager) {
return;
}
if (mViewPager != null) {
mViewPager.setOnPageChangeListener(null);
}
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
mViewPager = viewPager;
viewPager.setOnPageChangeListener(this);
notifyDataSetChanged();
setCurrentItem(initPos + 1);
}
notifyDataSetChangeListener()是根据pager的数目绘制圆点,注意圆点的数目比数组中的少两个,因为头和尾我们是不希望显示出来的
/**
* 初始化布局,逐个添加圆点
*/
private void notifyDataSetChanged(){
removeAllViews();
PagerAdapter mAdapter = mViewPager.getAdapter();
circleCount = mAdapter.getCount()-2;//少两个
for(int i=0;i<circleCount;i++){
addCircle(i);
}
requestLayout();
}
/**
* 添加圆点
* @param index
*/
private void addCircle(int index) {
CircleView circleView = new CircleView(getContext(),index,circleRadiu);
int circleWidth = 2*(circleRadiu+circlePadding);
LayoutParams lp = new LayoutParams(circleWidth, circleWidth,1);
circleView.setLayoutParams(lp);
addView(circleView);
}
其中圆点类,是我们自定义的
public class CircleView extends View {
public int index;
private static final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public int circleRadius;
public int color = Color.WHITE;
public CircleView(Context context, int index,int circleRadius){
this(context);
this.index = index;
this.circleRadius = circleRadius;
mPaint.setStrokeWidth(2);
}
public CircleView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isSelected()){
mPaint.setStyle(Paint.Style.FILL);
}else{
mPaint.setStyle(Paint.Style.STROKE);
}
mPaint.setColor(color);
//绘制空心圆
canvas.drawCircle(getWidth() / 2, getHeight() / 2, circleRadius, mPaint);
}
}
这个类可以根据自己是否处于selected状态,来选择怎么绘制自己,是绘制圆环还是实心圆
绘制圆点以后,setCurrentItem()将可以使viewpager滑动到某一页,并且改变圆点的状态
**
* 滑动页,同时改变相应的圆点状态
* @param item 当前页码
*/
public void setCurrentItem(int item) {
if (mViewPager == null) {
throw new IllegalStateException("ViewPager has not been bound.");
}
curIndex = item;
mViewPager.setCurrentItem(item);//viewpager滑动
if(item==0) item= circleCount-1;
else if(item==circleCount+1) item = 0;
else item = item-1;
for (int i = 0; i < circleCount; i++) {//遍历标题,改变选中的背景
CircleView child = (CircleView) getChildAt(i);
boolean isSelected = (i == item);
child.setSelected(isSelected);
}
}
另外,根据思路,我们要处理瞬间跳转的问题,就是当滑动到尾,我们使viewpager瞬间跳转到第二页(数组第二个元素)
我们监听viewpager的滑动状态,当滑动动画结束,判断是否需要跳转
@Override
public void onPageScrollStateChanged(int state) {
if(state==ViewPager.SCROLL_STATE_IDLE){//当滑动停止时,判断是否到达边界
if(curIndex<=0){
mViewPager.setCurrentItem(circleCount,false);//瞬间跳动到倒数第二页
curIndex = circleCount;
}else if(curIndex>=circleCount+1){
mViewPager.setCurrentItem(1,false);//瞬间跳动到第二页
curIndex = 1;
}
}
if(mListener!=null) mListener.onPageScrollStateChanged(state);
}
这样,无限循环就制作成功了,而且圆点indicator也有了,效果如图:
最后就是实现自动效果了,我们看startAutoScroll()方法
/**
* 开始自动滚动,必须主动调用
*/
public void startAutoScroll(){
myHandler.sendEmptyMessageDelayed(SCROLL_WHAT, spentTime);
}
也就是这里开始让hadler发送消息
/**
* 用于不断向主线程发送信息,使行状态改变
* 在handleMessage()里面调用sendMessageDelayed()可以实现自动无限滚动
*/
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case SCROLL_WHAT:
setCurrentItem(curIndex+direction);
myHandler.removeMessages(SCROLL_WHAT);
myHandler.sendEmptyMessageDelayed(SCROLL_WHAT, spentTime);//暂停一定时间,再次方式消息
break;
}
}
}
可以看到,我们暂停一定时间以后,再给handler自己发送消息
另外我们调用setCurrentItem()就可以让页面滑动,所以每次我们只要记录curindex就可以了
OK,文章讲到这里,可能没有以前的详细,因为这些原理都在之前的两篇文章介绍过了
如果大家有任何不明白,可以参考教你自定义竖直跑马灯效果(广告专用)
也可以给我留言,,源码地址http://download.csdn.net/detail/kangaroo835127729/9035225
转载请注明出处!