Android ViewPager 无限循环左右滑动(可自动) 实现

对于ViewPager 广告页 这个功能 很多APP都有这个功能
在网上也看过一些资料,我就在这把我自己完整的实现方法写出来吧 Demo放在最下面

基础的ViewPager:

<?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:id="@+id/top_item"
    android:orientation="vertical">

        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:id="@+id/top_vp"

            ></android.support.v4.view.ViewPager>

</LinearLayout>

很简单 仅仅是一个ViewPager
接下来简单的设置一下ViewPager的Adapter 添加ImageView

public class MainActivity extends AppCompatActivity {

    private ViewPager topVp;
    private int[]images = new int[]{R.mipmap.ad0, R.mipmap.ad1, R.mipmap.ad3};  //模拟存放要展示的图片
    private List<ImageView> imageViews ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initImageViews();
        initVp();
    }

    /**
     * 初始化图片资源
     */
    private void initImageViews() {
        imageViews = new ArrayList<>();
        for(int i = 0;i<images.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setImageResource(images[i]);
            imageViews.add(imageView);
        }
    }

    private void initVp() {

        topVp = (ViewPager) findViewById(R.id.top_vp);
        topVp.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
                return imageViews.size();
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view==object;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(imageViews.get(position));
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                container.addView(imageViews.get(position));
                return imageViews.get(position);
            }
        });
    }

}

上述是最基础的一个ViewPager 下面我们就在这个基础上改造就可以了

实现无限循环滑动:

这里我事先循环滑动的方式很简单 就是把 adapter的count 设置为一个很大的值 这样 让它滑不到头 然后切换图片 就可以实现 虽然方法比较LOW 但是效果还是可以的
代码在基础的ViewPager下修改如下 :

public class MainActivity extends AppCompatActivity {

    private ViewPager topVp;
    private int[]images = new int[]{R.mipmap.ad0, R.mipmap.ad1, R.mipmap.ad3};  //模拟存放要展示的图片
    private List<ImageView> imageViews ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initImageViews();
        initVp();
    }

    /**
     * 初始化图片资源
     */
    private void initImageViews() {
        imageViews = new ArrayList<>();
        for(int i = 0;i<images.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setImageResource(images[i]);
            imageViews.add(imageView);
        }
    }

    private void initVp() {

        topVp = (ViewPager) findViewById(R.id.top_vp);
        topVp.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
//                return imageViews.size(); 修改如下
                return 10000;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view==object;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
//                container.removeView(imageViews.get(position%imageViews.size())); 删除此句  此句不删除  会出现 滑动中 布局消失的情况  因为被移除了  此处这样修改会影响一些性能。。。。。
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
//                container.addView(imageViews.get(position));
//                return imageViews.get(position);  修改如下
                try {
                    container.addView(imageViews.get(position%imageViews.size()));
                }catch (Exception e){

                }
                return imageViews.get(position%imageViews.size());
            }
        });
    }

}

这样 之后就可以实现无限循环右滑了 但是在程序刚启动 是 无法向左滑动的 要解决 很简单 只需要在开始的时候
viewPager.setCurrentItem(1000*imageViews.size());
即可 这样 就可以 实现 无限左右滑了

自动定时循环滑动:

下面增加自动定时左右滑动的功能
要实现自动滑动 最主要的是 实现定时器功能
我这里使用 Handler+Runnable的方法
在上述代码的基础上 修改 如下:

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initImageViews();
        initVp();
        handler = new Handler();
        handler.postDelayed(new TimerRunnable(),5000);
    }

    class TimerRunnable implements Runnable{

        @Override
        public void run() {
            int curItem = topVp.getCurrentItem();
            topVp.setCurrentItem(curItem+1);
            if (handler!=null){
                handler.postDelayed(this,5000);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler = null; //此处在Activity退出时及时 回收
    }

这之后 就可以实现自动滑动了

添加左下角圆形小按钮:

接下来添加 左下角的导航小原点
首先 修改布局 :

<?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:id="@+id/top_item"
    android:orientation="vertical">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="180dp">


        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:id="@+id/top_vp"

            ></android.support.v4.view.ViewPager>
        <LinearLayout
            android:id="@+id/lin_points"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="10dp"
            android:layout_alignParentBottom="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >

        </LinearLayout>
    </RelativeLayout>


</LinearLayout>

我们需要的原点 要放在 LinearLayout布局中
主要原理 就是向这个LinearLayout中动态添加 小圆点 即可


public class MainActivity extends AppCompatActivity {

    private ViewPager topVp;
    private int[]images = new int[]{R.mipmap.ad0, R.mipmap.ad1, R.mipmap.ad3};  //模拟存放要展示的图片
    private List<ImageView> imageViews ;
    private List<TextView> txtPoints;
    private LinearLayout lin_points;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lin_points = (LinearLayout) findViewById(R.id.lin_points);
        initImageViews();
        initVp();

        initCircle();
        /*
         * 计时器
         */
        handler = new Handler();
        handler.postDelayed(new TimerRunnable(),5000);
    }

    /**
     * 初始化小圆点
     */
    private void initCircle() {
        txtPoints = new ArrayList<>();
        int d = 20;
        int m = 7;
        for (int i = 0; i < imageViews.size(); i++) {
            TextView txt = new TextView(this);
            if (i == 0) {
                txt.setBackgroundResource(R.drawable.point_pink);
            } else {
                txt.setBackgroundResource(R.drawable.point_grey);
            }
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(d, d);

            params.setMargins(m, m, m, m);
            txt.setLayoutParams(params);
            txtPoints.add(txt);
            lin_points.addView(txt);
        }
    }

    class TimerRunnable implements Runnable{

        @Override
        public void run() {
            int curItem = topVp.getCurrentItem();
            topVp.setCurrentItem(curItem+1);
            changePoints((curItem+1)%imageViews.size());
            if (handler!=null){
                handler.postDelayed(this,5000);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler = null;
    }

    /**
     * 初始化图片资源
     */
    private void initImageViews() {
        imageViews = new ArrayList<>();
        for(int i = 0;i<images.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setImageResource(images[i]);
            imageViews.add(imageView);
        }
    }


    private void initVp() {

        topVp = (ViewPager) findViewById(R.id.top_vp);
        topVp.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
//                return imageViews.size(); 修改如下
                return 10000;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view==object;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
//                container.removeView(imageViews.get(position%imageViews.size())); 删除此句
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
//                container.addView(imageViews.get(position));
//                return imageViews.get(position);  修改如下
                try {
                    container.addView(imageViews.get(position%imageViews.size()));
                }catch (Exception e){

                }
                return imageViews.get(position%imageViews.size());
            }
        });

        topVp.setCurrentItem(imageViews.size()*1000);

        topVp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                changePoints((position)%imageViews.size());
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }
    public void changePoints(int pos) {
        if (txtPoints != null) {
            for (int i = 0; i < txtPoints.size(); i++) {
                if (pos == i) {
                    txtPoints.get(i).setBackgroundResource(R.drawable.point_pink);
                } else {
                    txtPoints.get(i).setBackgroundResource(R.drawable.point_grey);
                }
            }
        }
    }
}

给ViewPager添加切换动画:

topVp.setPageTransformer(true,new CubeOutTransformer());
调用 此行代码 可以添加 后面的TransFormer类 是自定义的过渡效果类

控制ViewPager 自动切换的速度

ViewPager自身的切换速度是写死的,我们无法修改,但是我们可以通过源码看到,ViewPager的切换速度是通过 Scroller类 控制的,而Scroller类中是可以设置过渡的时间的,因此 我们可以通过自己创建一个Scroller类 继承 Scroller 然后 通过反射 把ViewPager中的mScroller属性 设置成我们自己的可以设置时间的Scroller类即可
下面是代码:

public class FixedSpeedScroller extends Scroller {
    private int mDuration = 1500;

    public FixedSpeedScroller(Context context) {
        super(context);
    }

    public FixedSpeedScroller(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    public void setmDuration(int time) {
        mDuration = time;
    }

    public int getmDuration() {
        return mDuration;
    }
}

反射修改ViewPager属性:

  try {
            Field field = ViewPager.class.getDeclaredField("mScroller");
            field.setAccessible(true);
            scroller = new FixedSpeedScroller(getActivity());
            scroller.setmDuration(1000);
            field.set(topVp, scroller);
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println("aaaaaa错误啦");
        }

这样 就可以控制速度了

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现 ViewPager 的循环滑动,可以通过以下步骤: 1. 继承 ViewPager 类,重写 `onTouchEvent` 方法,使其支持循环滑动。 ```java public class LoopViewPager extends ViewPager { public LoopViewPager(Context context) { super(context); } public LoopViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { stopAutoScroll(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { startAutoScroll(); } return super.onTouchEvent(event); } } ``` 2. 重写 `onMeasure` 方法,使其支持 wrap_content。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if (h > height) { height = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } ``` 3. 重写 `setAdapter` 方法,使其支持循环滑动。 ```java @Override public void setAdapter(PagerAdapter adapter) { super.setAdapter(adapter); setCurrentItem(0); } @Override public void setCurrentItem(int item) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item); return; } int position = getRealPosition(item); super.setCurrentItem(position); } private int getRealCount() { PagerAdapter adapter = getAdapter(); if (adapter == null) { return 0; } return adapter.getCount(); } private int getRealPosition(int position) { int realCount = getRealCount(); if (realCount == 0) { return 0; } return position % realCount; } ``` 4. 在 `onPageSelected` 回调中处理循环滑动的逻辑。 ```java @Override public void onPageSelected(int position) { int realCount = getRealCount(); if (realCount == 0) { return; } int realPosition = getRealPosition(position); if (realPosition == 0) { setCurrentItem(realCount, false); } else if (realPosition == realCount - 1) { setCurrentItem(1, false); } } ``` 5. 在 `startAutoScroll` 和 `stopAutoScroll` 方法中处理自动滑动的逻辑。 ```java private void startAutoScroll() { stopAutoScroll(); mHandler.postDelayed(mAutoScrollTask, mInterval); } private void stopAutoScroll() { mHandler.removeCallbacks(mAutoScrollTask); } private Runnable mAutoScrollTask = new Runnable() { @Override public void run() { int currentItem = getCurrentItem(); setCurrentItem(currentItem + 1, true); mHandler.postDelayed(this, mInterval); } }; ``` 完整的实现代码如下: ```java public class LoopViewPager extends ViewPager { private static final int DEFAULT_INTERVAL = 3000; private Handler mHandler = new Handler(); private int mInterval = DEFAULT_INTERVAL; public LoopViewPager(Context context) { super(context); init(); } public LoopViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setPageTransformer(true, new DefaultTransformer()); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { stopAutoScroll(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { startAutoScroll(); } return super.onTouchEvent(event); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if (h > height) { height = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override public void setAdapter(PagerAdapter adapter) { super.setAdapter(adapter); setCurrentItem(0); } @Override public void setCurrentItem(int item) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item); return; } int position = getRealPosition(item); super.setCurrentItem(position); } @Override public void setCurrentItem(int item, boolean smoothScroll) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item, smoothScroll); return; } int position = getRealPosition(item); super.setCurrentItem(position, smoothScroll); } @Override public int getCurrentItem() { int realCount = getRealCount(); if (realCount == 0) { return super.getCurrentItem(); } int position = super.getCurrentItem(); return getRealPosition(position); } private int getRealCount() { PagerAdapter adapter = getAdapter(); if (adapter == null) { return 0; } return adapter.getCount(); } private int getRealPosition(int position) { int realCount = getRealCount(); if (realCount == 0) { return 0; } return position % realCount; } @Override public void onPageSelected(int position) { int realCount = getRealCount(); if (realCount == 0) { return; } int realPosition = getRealPosition(position); if (realPosition == 0) { setCurrentItem(realCount, false); } else if (realPosition == realCount - 1) { setCurrentItem(1, false); } } public void setInterval(int interval) { mInterval = interval; } public void startAutoScroll() { stopAutoScroll(); mHandler.postDelayed(mAutoScrollTask, mInterval); } public void stopAutoScroll() { mHandler.removeCallbacks(mAutoScrollTask); } private Runnable mAutoScrollTask = new Runnable() { @Override public void run() { int currentItem = getCurrentItem(); setCurrentItem(currentItem + 1, true); mHandler.postDelayed(this, mInterval); } }; private static class DefaultTransformer implements ViewPager.PageTransformer { @Override public void transformPage(View page, float position) { if (position < -1) { page.setAlpha(0); } else if (position <= 1) { float scaleFactor = Math.max(0.75f, 1 - Math.abs(position - 0.125f)); page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); } else { page.setAlpha(0); } } } } ``` 使用方式: ```xml <com.example.LoopViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` ```java LoopViewPager viewPager = findViewById(R.id.view_pager); PagerAdapter adapter = new MyPagerAdapter(); viewPager.setAdapter(adapter); viewPager.setInterval(3000); viewPager.startAutoScroll(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值