GitHub源码地址:https://github.com/qiushi123/QCLAutoCycleView 欢迎star
先看效果图
package com.qclautocycleview;
import android.app.Activity;
import android.content.Context;
import android.os.SystemClock;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* 可以自动循环轮播的viewpager控件
* 实现功能
* 1,自动循环轮播,可以设置时间
* 2,可以手动实现循环滑动
*/
public class AutoCycleView extends RelativeLayout {
private final static String CYCLE_VIEW = "AtuoCycleView";//打印log用的
private List mViewList;
private ViewPager mViewpage;
private Activity mContext;
private CyclePagerAdapter mAdapter;
private CycleRunable mCycleRunable = new CycleRunable();
private CycleIndexView mCycleIdxView;//圆点
public AutoCycleView(Context context) {
super(context);
init(context);
}
public AutoCycleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AutoCycleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/*
* 初始化
* */
public void init(Context context) {
mViewList = new ArrayList();
/*
* 把viewpager和圆点添加到布局中
* */
mViewpage = new ViewPager(context);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mViewpage.setLayoutParams(layoutParams);
addView(mViewpage);
mViewpage.setAdapter(mAdapter = new CyclePagerAdapter());
mViewpage.addOnPageChangeListener(new CycleViewChangeListener());
//自定义滑动时的圆点
mCycleIdxView = new CycleIndexView(context);
addView(mCycleIdxView);
}
/*
* 传入所需的数据
* */
public void setViewList(List viewList, Activity mainActivity) {
mContext = mainActivity;
mViewList = viewList;
//增加循环项
mViewpage.setCurrentItem(1);
mAdapter.notifyDataSetChanged();
createIdxView(viewList.size() - 2);//创建和viewpager数据对应的圆点
}
/*
* 创建所需圆点
* */
public void createIdxView(int size) {
if (null != mCycleIdxView) {
mCycleIdxView.setViewCount(size);//设置圆点个数
LayoutParams layoutParams = new LayoutParams(mCycleIdxView.getCycleIdxViewWidth(), mCycleIdxView.getCycleIdxViewHeight());
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);//居于底部
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);//水平居中
mCycleIdxView.setLayoutParams(layoutParams);
}
}
/*
* 设置自动轮播时间间隔
* */
public void startCycle(long time) {
mCycleRunable.setCycleTime(time);
mCycleRunable.startCycle();
}
/*
* 开启循环
* */
public void startCycle() {
mCycleRunable.startCycle();
}
/*
* viewpager对应的适配器
* */
public class CyclePagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return mViewList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
LayoutInflater inflater = mContext.getLayoutInflater();
View view = inflater.inflate(R.layout.pager_item, null);
TextView tv = (TextView) view.findViewById(R.id.text);
tv.setText(mViewList.get(position));
container.addView(view);
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(mContext, "点击了" + mViewList.get(position), Toast.LENGTH_SHORT).show();
}
});
return view;
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
if (action == MotionEvent.ACTION_DOWN) {
//暂停自动滚动
mCycleRunable.puaseCycle();
} else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
//启动自动滚动
mCycleRunable.startCycle();
}
return super.dispatchTouchEvent(ev);
}
/*
* 轮播实现
* */
public void changePager() {
if (mViewList.isEmpty()) {
Log.e(CYCLE_VIEW, "data is empty!");
throw new IllegalStateException("data is empty!");
}
int item = Math.min(mViewpage.getCurrentItem(), mViewList.size() - 1);
//mViewpage.setCurrentItem(++item);
if (item == mViewList.size() - 1) {
mViewpage.setCurrentItem(0);
} else {
mViewpage.setCurrentItem(++item);
}
}
/*
*
* */
class CycleRunable implements Runnable {
private boolean isAnimotion = false;
private long mDefaultCycleTime = 1000L;//设置默认轮播时间 单位毫秒
private long mLastTime;
public void setCycleTime(long time) {
mDefaultCycleTime = time;
}
@Override
public void run() {
if (isAnimotion) {
long now = SystemClock.currentThreadTimeMillis();
if (now - this.mLastTime >= this.mDefaultCycleTime) {
changePager();//大于指定时间间隔时就轮播下一个
this.mLastTime = now;
}
AutoCycleView.this.post(this);
}
}
public void startCycle() {//开启自动循环
if (this.isAnimotion) {
return;
}
this.mLastTime = SystemClock.currentThreadTimeMillis();
this.isAnimotion = true;
AutoCycleView.this.post(this);
}
public void puaseCycle() {//暂停自动轮播
this.isAnimotion = false;
}
}
class CycleViewChangeListener implements ViewPager.OnPageChangeListener {
//用户自己
private boolean needJumpToRealPager = true;
public void setNeedJumpFlag(boolean isNeedJump) {
needJumpToRealPager = isNeedJump;
}
public boolean getNeedJumpFlag() {
return needJumpToRealPager;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
// Log.d(CYCLE_VIEW, "onPageSelected position is "+position);
if (null != mCycleIdxView && mViewpage.getCurrentItem() != 0 && mViewpage.getCurrentItem() != mViewList.size() - 1) {
mCycleIdxView.setCurIndex(position - 1);//绑定圆点和viewpager的条目
}
//如果是头或者尾,等滑动
if (mViewpage.getCurrentItem() == 0 && getNeedJumpFlag()) {
setNeedJumpFlag(false);
mViewpage.setCurrentItem(mViewList.size() - 1, false);
mViewpage.setCurrentItem(mViewList.size() - 2);
} else if (mViewpage.getCurrentItem() == mViewList.size() - 1 && getNeedJumpFlag()) {
setNeedJumpFlag(false);
mViewpage.setCurrentItem(0, false);
mViewpage.setCurrentItem(1);
} else {
setNeedJumpFlag(true);
}
// mViewpage
}
@Override
public void onPageScrollStateChanged(int state) {
// Log.d(CYCLE_VIEW, "onPageScrollStateChanged state is "+state);
}
}
}
package com.qclautocycleview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* 自定义圆点
*/
public class CycleIndexView extends View {
private int mViewCount = 5;
private IdxCircle mIdxCircle;
private int mCurViewIndex = 0;
public CycleIndexView(Context context) {
this(context, null);
}
public CycleIndexView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CycleIndexView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
float density = context.getResources().getDisplayMetrics().density;
mIdxCircle = new IdxCircle(density);
}
/*
* 设置圆点个数
* */
public void setViewCount(int count) {
mViewCount = count;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawIndexPoint(canvas);
}
public void drawIndexPoint(Canvas canvas) {
final int saveCount = canvas.save();
for (int i = 0; i < mViewCount; i++) {
boolean isCurView = (i == mCurViewIndex);
mIdxCircle.draw(canvas, i, isCurView);
}
canvas.restoreToCount(saveCount);
}
public int getCycleIdxViewHeight() {
return mIdxCircle.getHeight();
}
public int getCycleIdxViewWidth() {
return mIdxCircle.getRadius() * 2 * mViewCount + mIdxCircle.getSpace() * (mViewCount - 1);
}
//绑定圆点和viewpager的条目
public void setCurIndex(int idx) {
mCurViewIndex = idx % mViewCount;
invalidate();//重绘
}
private class IdxCircle {
private int mAngle = 45;
private Paint mPaint = new Paint();
private int mCircleRadius = 2;//设置圆点半径
private int mSpace = 5;//设置圆点间隔
private float mDensity = 1;
public IdxCircle(float density) {
mDensity = density;
mCircleRadius = (int) (mCircleRadius * density);
mSpace = (int) (mSpace * density);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setColor(Color.WHITE);
}
public void draw(Canvas canvas, int i, boolean isCurPosition) {
final int saveCount = canvas.save();
// final int alpha = isCurPosition ? 5 : 160;
// mPaint.setAlpha(alpha);//设置透明度
if (!isCurPosition) {
mPaint.setColor(0xffbfbfbf);//设置未选中的点的颜色
} else {
mPaint.setColor(0xffffffff);//设置选中的点的颜色
}
canvas.translate(mCircleRadius + i * (mSpace + 2 * mCircleRadius), mCircleRadius);
canvas.drawCircle(0, 0, mCircleRadius, mPaint);
canvas.restoreToCount(saveCount);
}
public int getHeight() {
return mCircleRadius * 4;//设置圆点布局的高度
}
public int getRadius() {
return mCircleRadius;
}
public int getSpace() {
return mSpace;
}
}
}
public class MainActivity extends AppCompatActivity {
public AutoCycleView cycleView;
List mViewList = new ArrayList();//顶部用于循环的布局集合
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cycleView = (AutoCycleView) findViewById(R.id.cycle_view);
initCycleViewPager();
cycleView.setViewList(mViewList, this);
cycleView.startCycle();//开始自动滑动
}
/*
* 添加顶部循环滑动数据
* 添加数据的时候需要注意在正常数据的基础上把最后一个数据添加到第一个前面,把第一个数据添加到最后一个数据后面,用来循环
* 比如一共有1,2,3三个数据,为了实现循环需要另外添加两个数据,
* 这样数据就成了3,1,2,3,1 这样就可以实现循环滑动的效果了
* */
public void initCycleViewPager() {
mViewList = new ArrayList();
mViewList.add("第五页");
mViewList.add("第一页");
mViewList.add("第二页");
mViewList.add("第三页");
mViewList.add("第四页");
mViewList.add("第五页");
mViewList.add("第一页");
}
}
至此就可以实现自动无线轮播viewpager的效果了。是不是特别简单
如有疑问可以微信我2501902696(备注安卓)