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<String> 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<String>(); /* * 把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<String> 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); } }}上面使用到的簡單布局pager_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:background="#00ffff" android:orientation="vertical"> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="pager1"/></LinearLayout>二,自定義和上面搭配使用的圓點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<String> mViewList = new ArrayList<String>();//頂部用于循環的布局集合 @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<String>(); mViewList.add("第五頁"); mViewList.add("第一頁"); mViewList.add("第二頁"); mViewList.add("第三頁"); mViewList.add("第四頁"); mViewList.add("第五頁"); mViewList.add("第一頁"); }}再看下activity_main只需要把AutoCycleView作為一個view控件使用就可以了<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.qclautocycleview.AutoCycleView android:id="@+id/cycle_view" android:layout_width="match_parent" android:layout_height="300dp"/></RelativeLayout>至此就可以實現自動無線輪播viewpager的效果了。是不是特別簡單
如有疑問可以微信我2501902696(備注安卓)
新聞熱點
疑難解答