美文网首页Android开发学习
使用ViewPager实现图片轮播

使用ViewPager实现图片轮播

作者: 李俊的博客 | 来源:发表于2016-08-06 09:15 被阅读7285次

    前言

    首先我们来看一下运行的效果,如下所示:



      这是在我们的项目中经常会用到的图片轮播效果,一般用于广告图片的展示。

    它要求主要实现以下功能:

    1)自动播放;
      2)无限滑动;
      3)手指拖拽图片时暂停自动轮播,松开后继续自动轮播;
      4)含动画效果的小圆点指示器。

    本文将介绍利用ViewPager实现无限轮播图片,图片下方加上小圆点指示器标记当前位置,并利用Handler实现自动轮播图片。

    正文

    1、实现自动播放
    思路:没隔一段时间让ViewPager更换一次页卡,使用Handler来实现。

    1)标记是否自动播放

    private boolean isAutoPlay;
    

    2)每隔一段时间使用Handler发送一次更换页卡的任务

    // 如果少于2张就不用自动播放了
    if (count < 2) {
        isAutoPlay = false;
    } else {
        isAutoPlay = true;
        handler = new Handler();
        handler.postDelayed(task, delay);
    }
    

    3)在任务中每隔一段时间再次发送任务,这样循环发送就实现了自动播放的效果。

    private Runnable task = new Runnable() {
        @Override
        public void run() {
            if (isAutoPlay) {
                // 位置循环
                currentItem = currentItem % (count + 1) + 1;
                // 正常每隔3秒播放一张图片
                vpImageTitle.setCurrentItem(currentItem);
                handler.postDelayed(task, delay);
            } else {
                // 如果处于拖拽状态停止自动播放,会每隔5秒检查一次是否可以正常自动播放。
                handler.postDelayed(task, 5000);
            }
        }
    };
    

    2、实现无限滑动
    思路:设置页卡视图列表时,在前后额外各加一个页卡。最前面加最后一张图片,最后面加第1张图片。然后每当切换到最前的页卡时,就替换成倒数第2个页卡;每当切换到最后的页卡时,就替换成第2个页卡。这样一来就形成了连贯,自然实现了无限滑动的功能。

    1)设置ViewPager的视图列表时,在前后各加一个页卡。

    for (int i = 0; i < count + 2; i++) {
        if (i == 0) {// 将最前面一页设置成本来最后的那页
            Glide.with(context).
                    load(imageTitleBeanList.get(count - 1).getImageUrl()).into(ivImage);
            tvTitle.setText(imageTitleBeanList.get(count - 1).getTitle());
        } else if (i == count + 1) {// 将最后面一页设置成本来最前的那页
            Glide.with(context).
                    load(imageTitleBeanList.get(0).getImageUrl()).into(ivImage);
            tvTitle.setText(imageTitleBeanList.get(0).getTitle());
        } else {
            Glide.with(context).
                    load(imageTitleBeanList.get(i - 1).getImageUrl()).into(ivImage);
            tvTitle.setText(imageTitleBeanList.get(i - 1).getTitle());
        }
        // 将设置好的View添加到View列表中
        viewList.add(view);
    }
    

    2)在监听ViewPager的页卡状态改变中,当滑动到第1个页卡时替换成倒数第2个页卡;当滑动到最后一个页卡时替换成第2个页卡。

    @Override
    public void onPageScrollStateChanged(int state) {
        switch (state) {
            // 闲置中
            case ViewPager.SCROLL_STATE_IDLE:
                // “偷梁换柱”
                if (vpImageTitle.getCurrentItem() == 0) {
                    vpImageTitle.setCurrentItem(count, false);
                } else if (vpImageTitle.getCurrentItem() == count + 1) {
                    vpImageTitle.setCurrentItem(1, false);
                }
                currentItem = vpImageTitle.getCurrentItem();
                break;
        }
    }
    

    3、手指滑动图片时停止自动播放
    思路:使用一个标记来控制是否自动播放。

    1)声明一个boolean变量,用来标记是否播放。

    private boolean isAutoPlay;
    

    2)默认是自动播放,但当图片少于2张时不自动播放。

    private void starPlay() {
        // 如果少于2张就不用自动播放了
        if (count < 2) {
            isAutoPlay = false;
        } else {
            isAutoPlay = true;
            handler.postDelayed(task, delay);
        }
    }
    

    3)根据标记判断是否切换页卡

    private Runnable task = new Runnable() {
        @Override
        public void run() {
            if (isAutoPlay) {
                // 正常每隔3秒播放一张图片
                vpImageTitle.setCurrentItem(currentItem);
                handler.postDelayed(task, delay);
            } else {
                // 如果处于拖拽状态停止自动播放,会每隔5秒检查一次是否可以正常自动播放。
                handler.postDelayed(task, 5000);
            }
        }
    };
    

    4)在监听ViewPager的页卡状态改变中,如果是拖动状态就不切换页卡。

    @Override
    public void onPageScrollStateChanged(int state) {
        switch (state) {
            // 闲置中
    
            case ViewPager.SCROLL_STATE_IDLE:
                isAutoPlay = true;
                break;
            // 拖动中
            case ViewPager.SCROLL_STATE_DRAGGING:
                isAutoPlay = false;
                break;
            // 设置中
            case ViewPager.SCROLL_STATE_SETTLING:
                isAutoPlay = true;
                break;
        }
    }
    

    4、自定义指示器
    思路:使用一个LinearLayout作为容器,然后根据图片的数量向容器中不断添加绘制的小圆点,另外再设置变大变小的属性动画用于动画效果。监听ViewPager的页卡,每当切换到一个页卡时就将切换对应状态的小圆点,并且设置相应的动画效果。

    1)绘制小圆点
    未选中状态,灰色的圆。

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
          android:shape="oval">
        <size
            android:width="32dp"
            android:height="32dp"/>
        <solid android:color="#9e9e9e"/>
    </shape>
    

    选中状态,白色的圆。

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
          android:shape="oval">
        <size
            android:width="32dp"
            android:height="32dp"/>
        <solid android:color="#ecf0f1"/>
    </shape>
    

    2)属性动画
    变大

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectAnimator
            android:duration="150"
            android:pivotX="50%"
            android:pivotY="50%"
            android:propertyName="scaleX"
            android:valueFrom="1.0"
            android:valueTo="1.5"
            android:valueType="floatType"/>
        <objectAnimator
            android:duration="150"
            android:pivotX="50%"
            android:pivotY="50%"
            android:propertyName="scaleY"
            android:valueFrom="1.0"
            android:valueTo="1.5"
            android:valueType="floatType"/>
    </set>
    

    变小

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectAnimator
            android:duration="150"
            android:pivotX="50%"
            android:pivotY="50%"
            android:propertyName="scaleX"
            android:valueFrom="1.5"
            android:valueTo="1.0"
            android:valueType="floatType"/>
        <objectAnimator
            android:duration="150"
            android:pivotX="50%"
            android:pivotY="50%"
            android:propertyName="scaleY"
            android:valueFrom="1.5"
            android:valueTo="1.0"
            android:valueType="floatType"/>
    </set>
    

    3)设置指示器
    先是统一设置属性并添加到容器中,然后默认第1个小圆点为选中状态。选中状态的小圆点颜色由灰色变成白色,并且变大。

    private void setIndicator() {
        isLarge = new SparseBooleanArray();
        // 记得创建前先清空数据,否则会受遗留数据的影响。
        llDot.removeAllViews();
        for (int i = 0; i < count; i++) {
            View view = new View(context);
            view.setBackgroundResource(R.drawable.dot_unselected);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(dotSize, dotSize);
            layoutParams.leftMargin = dotSpace / 2;
            layoutParams.rightMargin = dotSpace / 2;
            layoutParams.topMargin = dotSpace / 2;
            layoutParams.bottomMargin = dotSpace / 2;
            llDot.addView(view, layoutParams);
            isLarge.put(i, false);
        }
        llDot.getChildAt(0).setBackgroundResource(R.drawable.dot_selected);
        animatorToLarge.setTarget(llDot.getChildAt(0));
        animatorToLarge.start();
        isLarge.put(0, true);
    }
    

    4)监听页卡
    当页卡被选中时,相应的小圆点颜色由灰色变成白色,并且变大;之前的小圆点颜色由白色变成灰色,并且变小。

    @Override
    public void onPageSelected(int position) {
        // 遍历一遍子View,设置相应的背景。
        for (int i = 0; i < llDot.getChildCount(); i++) {
            if (i == position - 1) {// 被选中
                llDot.getChildAt(i).setBackgroundResource(R.drawable.dot_selected);
                if (!isLarge.get(i)) {
                    animatorToLarge.setTarget(llDot.getChildAt(i));
                    animatorToLarge.start();
                    isLarge.put(i, true);
                }
            } else {// 未被选中
                llDot.getChildAt(i).setBackgroundResource(R.drawable.dot_unselected);
                if (isLarge.get(i)) {
                    animatorToSmall.setTarget(llDot.getChildAt(i));
                    animatorToSmall.start();
                    isLarge.put(i, false);
                }
            }
        }
    }
    

    源码地址
    ImageSlideshow

    相关文章

      网友评论

      • 61420ffceff9:当手指滑动很快的时候,viewpager还是会卡住,有更好的方式去实现无限循环吗
      • liouville:无限滑动的实现的思路很妙
      • cc07e99cee9c:指示器小圆点最后一个图片切换到第一个图片的时候感觉会慢一些。。。选中状态和缩放动画都会慢一些。。一直没找到原因。。想问下楼主有思路吗。。。

      本文标题:使用ViewPager实现图片轮播

      本文链接:https://www.haomeiwen.com/subject/uimcsttx.html