当前位置:网站首页>一行代码快速实现今日头条 网易新闻焦点图自动循环轮播效果

一行代码快速实现今日头条 网易新闻焦点图自动循环轮播效果

2021-08-08 15:40:48 编程小石头

有时候我们需要顶部焦点图可以自动轮播并且左右滑动时可以循环轮播,下面就来自定义这样的控件来实现,使用起来特别简单
实现功能
1,自动循环轮播,可以设置时间
2,可以手动实现循环滑动
3,可以自定义轮播时圆点大小和颜色

先看效果图


使用起来也特别简单,直接把下面的自定义控件复制到你的项目中,就可以一行代码快速实现自动无限轮播效果了。


一,自定义可以自动轮播的控件

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);


        }
    }
}

     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
  • 312.
  • 313.
  • 314.
  • 315.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
  • 333.
  • 334.
  • 335.
  • 336.
  • 337.
  • 338.




上面使用到的简单布局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>


     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.




二,自定义和上面搭配使用的圆点

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;
        }
    }
}

     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.



三,上面完事以后,就看使用了,使用起来特别方便

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("第一页");
    }
}

     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.



再看下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>

     
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.





至此就可以实现自动无线轮播viewpager的效果了。是不是特别简单

 

版权声明
本文为[编程小石头]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_14368928/3312687

随机推荐