viewpager循环滚动_jq实现轮播图循环

viewpager循环滚动_jq实现轮播图循环Viewpager图片自动轮播无限循环是Android开发中经常用到的功能,功能实现起来也比较简单。虽然如此,但是很多情况下做出来的效果并不太让人满意,甚至有些上线的项目自动轮播上也会出现一些bug。比如切换过程中出现空白页面,有些甚至在滑动过程中造成程序崩溃。本篇文章将实现ViewPager图片自动轮播无限循环,而且页面切换效果非常流畅。还是先看效果图:页面循环切换最容易出现问题的地方…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

Github 获取最新版本

Viewpager图片自动轮播无限循环是Android项目中经常用到的功能,功能实现起来也比较简单,但会出现不少问题。因此很多情况下做出来的效果并不太让人满意,甚至有些上线的项目自动轮播上也会出现一些bug。比如切换过程中出现空白页面,有些甚至在滑动过程中造成程序崩溃。本文内容对ViewPager进行封装,实现了可循环轮播的CirclSeViewPager,** 该控件有较强的可扩展性,可接受任意类型的集合数据,可以自定义任意的轮播页面样式。页面切换也比较流畅。**

先看效果图:
示例

接下来将通过以下几个小节对CircleViewPager做具体的分析。

  • 如何使用CircleViewPager
  • CircleViewPager的实现思路
  • CircleViewPager具体实现
  • CircleViewPager实现自动轮播
  • CircleViewPager页面点击事件

如果只是想实现无限轮播的效果那么只需看第一节即可,源码可在文章末尾下载。

一、如何使用CircleViewPager.。
CircleViewPager的使用非常简单,只需要几行代码就可实现,使用方法如下:
1.gradle中添加依赖


2.在xml文件中添加如下代码:

<com.zhpan.viewpager.view.CircleViewPager android:id="@+id/viewpager2" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginEnd="35dp" android:layout_marginStart="35dp" app:interval="5000" />

3.CircleViewPager属性

		// 是否显示指示器
        mViewpager.isShowIndicator(true);
		// 设置指示器位置
        mViewpager.setIndicatorGravity(CircleViewPager.IndicatorGravity.END);
        // 设置指示器圆点半径
        mViewpager.setIndicatorRadius(6);
		// 设置圆点指示器颜色 
		mViewPager.setIndicatorColor(getResources().getColor(R.color.colorAccent),
                getResources().getColor(R.color.colorPrimary));          
        // 设置是否无限循环
        mViewpager.setCanLoop(true);        
        // 设置是否自动轮播
        mViewpager.setAutoPlay(true);
        // 设置图片切换时间间隔
        mViewpager.setInterval(3000);
        // 设置页面点击事件
        mViewpager.setOnPageClickListener(new CircleViewPager.OnPageClickListener() { 
   
            @Override
            public void onPageClick(int position) { 
   
                List<DataBean> list = mViewpager.getList();
                Toast.makeText(MainActivity.this, "点击了" + list.get(position).getDescribe(), Toast.LENGTH_SHORT).show();
            }
        });
        // 设置数据
        mViewpager.setPages(mList, new HolderCreator<ViewHolder>() { 
   
            @Override
            public ViewHolder createViewHolder() { 
   
                return new MyViewHolder();
            }
        });

4.自定义ViewHolder

public class MyViewHolder implements ViewHolder<String> { 
   
            private ImageView mImageView;

            @Override
            public View createView(Context context) { 
   
                // 返回页面布局文件
                View view = LayoutInflater.from(context).inflate(R.layout.banner_item, null);
                mImageView = (ImageView) view.findViewById(R.id.banner_image);
                return view;
            }

            @Override
            public void onBind(Context context, int position, String data) { 
   
	            // 数据绑定
		        ImageLoaderUtil.loadImg(mImageView, (String) data);
            }
        }

5.为防止内存泄露在onDestory()中停止图片轮播

	@Override
    protected void onDestroy() { 
   
        super.onDestroy();
        mViewpager.stopLoop();
    }

二、CircleViewPager的实现思路
页面循环切换最容易出现问题的地方就是在最后一页向第一页切换或者第一页向最后一页切换时,在这个切换过程中很容易出现空白页面。怎么解决这个问题?
CircleViewPager的实现的思路是在第一张图片前和最后一张图片后分别添加一个ImageView,最前边的ImageView背景设置为最后一张图片,最后一个ImageView背景设置第一张图片。当我们判断滑动到最后一个ImageView时则设置ViewPager.setCurrentItem(1),让其自动切换到第一张图片,这样在从最后一页切换到第一页时由于图片是用的同一张图片,所以就会使切换效果显得很流畅自然。同理,当向左滑动到第0个ImageView时用ViewPager.setCurrentItem(length)自动切换到倒数第二张图片,第0个ImageView和倒数第二个ImageView图片相同,这样就使滑动效果显得很自然。

三、CircleViewPager具体实现
1.添加自定义属性。以在value目录下创建attrs.xml文件,文件中我们可以定义一些用到的属性,attrs.xml中定义的属性如下:

<resources>
    <declare-styleable name="MyViewPager">
        <!--选中时的圆点图片-->
        <attr name="lightDotRes" format="reference"/>
        <!--未选中时的圆点图片-->
        <attr name="darkDotRes" format="reference"/>
        <!--圆点半径-->
        <attr name="dotWidth" format="dimension"/>
        <!--页面切换时间间隔-->
        <attr name="interval" format="integer"/>
    </declare-styleable>
</resources>

2.新建CircleViewPager的布局文件view_pager_layout.xml,代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.v4.view.ViewPager android:id="@+id/vp_main" android:layout_width="match_parent" android:layout_height="match_parent" />

    <LinearLayout android:id="@+id/ll_main_dot" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignBottom="@id/vp_main" android:layout_marginBottom="10dp" android:gravity="center_horizontal" android:orientation="horizontal" />
</RelativeLayout>

3.定义CircleViewPager类并继承FrameLayout,并在构造方法中初始化数据,代码如下:

 public CircleViewPager(Context context) { 
   
        super(context);
        init(null);
    }

    public CircleViewPager(Context context, AttributeSet attrs) { 
   
        this(context, attrs, 0);
        init(attrs);
    }

    public CircleViewPager(Context context, AttributeSet attrs, int defStyleAttr) { 
   
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
   
        super.onLayout(changed, left, top, right, bottom);
        if (changed) { 
   
            initData();
            setIndicatorImage();
            setViewPager();
            setIndicatorLocation();
        }
    }

    private void init(AttributeSet attrs) { 
   
        if (attrs != null) { 
   
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CircleViewPager);
            mLightIndicator = typedArray.getResourceId(R.styleable.CircleViewPager_lightDotRes, R.drawable.red_dot);
            mDarkIndicator = typedArray.getResourceId(R.styleable.CircleViewPager_darkDotRes, R.drawable.red_dot_night);
            mDotWidth = typedArray.getDimension(R.styleable.CircleViewPager_dotWidth, 20);
            interval = typedArray.getInteger(R.styleable.CircleViewPager_interval, 3000);
            typedArray.recycle();
        }
         mView = LayoutInflater.from(getContext()).inflate(R.layout.view_pager_layout, this);
        mLlDot = (LinearLayout) mView.findViewById(R.id.ll_main_dot);
        mViewPager = (ViewPager) mView.findViewById(R.id.vp_main);
        mList = new ArrayList<>();
        mListAdd = new ArrayList<>();
        mIvDotList = new ArrayList<>();
    }

4.重写onLayout()方法,根据图片URL集合创建图片对应的ImageVIew和小圆点对应的ImageView.

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
   
        super.onLayout(changed, left, top, right, bottom);
        if (changed) { 
   
            initData();
            setIndicatorImage();
            setViewPager();
            setIndicatorLocation();
        }
    }
    
    // 根据mList数据集构造mListAdd
    private void initData() { 
   
        if (mList.size() == 0) { 
   
            mView.setVisibility(GONE);
        } else if (mList.size() == 1) { 
   
            mListAdd.add(mList.get(0));
        } else if (mList.size() > 1) { 
   
            for (int i = 0; i < mList.size() + 2; i++) { 
   
                if (i == 0) { 
      // 判断当i=0为该处的mList的最后一个数据作为mListAdd的第一个数据
                    mListAdd.add(mList.get(mList.size() - 1));
                } else if (i == mList.size() + 1) { 
      // 判断当i=mList.size()+1时将mList的第一个数据作为mListAdd的最后一个数据
                    mListAdd.add(mList.get(0));
                } else { 
     // 其他情况
                    mListAdd.add(mList.get(i - 1));
                }
            }
        }
    }

   // 设置轮播小圆点
    private void setIndicatorImage() { 
   
        // 设置LinearLayout的子控件的宽高,这里单位是像素。
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((int) mDotWidth, (int) mDotWidth);
        params.rightMargin = (int) (mDotWidth / 1.5);
        if (mList.size() > 1) { 
   
            // for循环创建mUrlList.size()个ImageView(小圆点)
            for (int i = 0; i < mList.size(); i++) { 
   
                ImageView imageViewDot = new ImageView(getContext());
                imageViewDot.setLayoutParams(params);
                // 设置小圆点的背景为暗红图片
                imageViewDot.setBackgroundResource(mDarkIndicator);
                mLlDot.addView(imageViewDot);
                mIvDotList.add(imageViewDot);
            }
        }
        //设置第一个小圆点图片背景为红色
        if (mList.size() > 1) { 
   
            mIvDotList.get(dotPosition).setBackgroundResource(mLightIndicator);
        }
    }

5.为ViewPager适配数据

 private void setViewPager() { 
   
        CirclePagerAdapter<T> adapter = new CirclePagerAdapter<>(mListAdd, this, holderCreator);
        mViewPager.setAdapter(adapter);
        mViewPager.setCurrentItem(currentPosition);

        setPageChangeListener();
        startLoop();
        setTouchListener();
        if (showIndicator) { 
   
            mLlDot.setVisibility(VISIBLE);
        } else { 
   
            mLlDot.setVisibility(GONE);
        }
    }

6.接下来为ViewPager添加页面改变的监听事件。

// ViewPager页面改变监听
    private void setPageChangeListener() { 
   
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
   
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
   
			}

            @Override
            public void onPageSelected(int position) { 
   
                pageSelected(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) { 
   
                // 当state为SCROLL_STATE_IDLE即没有滑动的状态时切换页面
                if (state == ViewPager.SCROLL_STATE_IDLE) { 
   
                    mViewPager.setCurrentItem(currentPosition, false);
                }
            }
        });
    }

private void pageSelected(int position) { 
   
        if (position == 0) { 
       //判断当切换到第0个页面时把currentPosition设置为list.size(),即倒数第二个位置,小圆点位置为length-1
            currentPosition = mList.size();
            dotPosition = mList.size() - 1;
        } else if (position == mList.size() + 1) { 
       //当切换到最后一个页面时currentPosition设置为第一个位置,小圆点位置为0
            currentPosition = 1;
            dotPosition = 0;
        } else { 
   
            currentPosition = position;
            dotPosition = position - 1;
        }
        // 把之前的小圆点设置背景为暗红,当前小圆点设置为红色
        mIvDotList.get(prePosition).setBackgroundResource(mDarkIndicator);
        mIvDotList.get(dotPosition).setBackgroundResource(mLightIndicator);
        prePosition = dotPosition;
    }

至此,ViewPager已经可以实现滑动,并且圆点也会跟随页面滑动而改变。
四、CircleViewPager实现自动轮播
1.自动轮播的实现,在第三节第5步的setViewPager()方法中调用下面startLoop()方法即可开启自动轮播

 Handler mHandler = new Handler();
    Runnable mRunnable = new Runnable() { 
   
        @Override
        public void run() { 
   
            if (mViewPager.getChildCount() > 1) { 
   
                mHandler.postDelayed(this, interval);
                currentPosition++;
                mViewPager.setCurrentItem(currentPosition, true);
            }
        }
    };

private void startLoop() { 
   
        if (!isLoop && mViewPager != null) { 
   
            mHandler.postDelayed(mRunnable, interval);// 每两秒执行一次runnable.
            isLoop = true;
        }
    }

2.自动轮播实现后发现会有些问题,即在手动滑动页面时,页面仍然会自动切换。这样体验效果是非常不好的,因此我们需要在手动滑动时停止自动轮播,当手动滑动结束时再开启自动轮播。因此我们可以重写ViewPager的onTouch事件进行处理,当触发ACTION_DOWN和ACTION_MOVE时停止自动轮播,当触发ACTION_UP和ACTION_CANCEL时再开启自动轮播。代码实现如下:

// 设置触摸事件,当滑动或者触摸时停止自动轮播
    private void setTouchListener() { 
   
        mViewPager.setOnTouchListener(new OnTouchListener() { 
   
            @Override
            public boolean onTouch(View v, MotionEvent event) { 
   
                int action = event.getAction();
                switch (action) { 
   
                    case MotionEvent.ACTION_DOWN:
                    case MotionEvent.ACTION_MOVE:
                        isLoop = true;
                        stopLoop();
                        break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        isLoop = false;
                        startLoop();
                    default:
                        break;
                }
                return false;
            }
        });
    }

	private void startLoop() { 
   
        if (!isLoop && mViewPager != null) { 
   
            mHandler.postDelayed(mRunnable, interval);// 每interval秒执行一次runnable.
            isLoop = true;
        }
    }
    
	public void stopLoop() { 
   
        if (isLoop && mViewPager != null) { 
   
            mHandler.removeCallbacks(mRunnable);
            isLoop = false;
        }
    }

至此,CircleViewPager的核心功能已经实现。但是页面的点击事件还未进行处理。接下来将在第五节中实现CircleViewPager的页面点击事件。
五、CircleViewPager页面点击事件。
1.页面的点击事件是通过点击ImageView触发的,因此我们可以首先考虑给页面的ImageView设置点击事件的监听。在哪里设置点击事件?无疑在Adapter中设置是比较简单的,因此我们在CircleViewPager的Adapter中对ImageView添加点击事件监听。如下:

  @Override
    public Object instantiateItem(final ViewGroup container, final int position) { 
   
        View view = getView(position, container);
        container.addView(view);
        return view;
    }
    
	// 根据图片URL创建对应的ImageView并添加到集合
    private View getView(final int position, ViewGroup container) { 
   
        ViewHolder holder = holderCreator.createViewHolder();
        if (holder == null) { 
   
            throw new RuntimeException("can not return a null holder");
        }
        View view = holder.createView(container.getContext());
        if (list != null && list.size() > 0) { 
   
            holder.onBind(container.getContext(), position, list.get(position));
        }
        view.setOnClickListener(new View.OnClickListener() { 
   
            @Override
            public void onClick(View v) { 
   
                viewPager.imageClick(position - 1);
            }
        });
        return view;
    }

我们事先在CircleViewPager中定义imageClick()方法,在实例化Adapter的时候将CircleViewPager自身传递进来,然后就可以在Adapter调用imageClick()方法。即图片被点击的时候会触发到CircleViewPager中的imageClick()方法。
2.模仿Android中View的监听事件来为CircleViewPager设置点击页面的事件监听。在CircleViewPager中定义OnPageClickListener接口,并在接口中定义pageClickListener(int position)的抽象方法。然后在CircleViewPager中定义OnPageClickListener的成员变量mOnPageClickListener,并为其设置set()方法。然后在imageClick()方法中调用mOnPageClickListener.pageClickListener(int position)。代码实现如下:

    private OnPageClickListener mOnPageClickListener;

		public void setOnPageClickListener(OnPageClickListener onPageClickListener) { 
   
        this.mOnPageClickListener = onPageClickListener;
    }
	
    // adapter中图片点击的回掉方法
    public void imageClick(int position) { 
   
        mOnPageClickListener.pageClickListener(position);
    }

	 // 监听页面点击的接口
	 public interface OnPageClickListener { 
   
        void pageClickListener(int position);
    }

3.MainActivity中设置页面点击的监听。通过CicleViewPager.setOnPageClickListener实现对页面点击的监听。

mViewpager.setOnPageClickListener(new CircleViewPager.OnPageClickListener() { 
   
            @Override
            public void pageClickListener(int position) { 
   
                Toast.makeText(MainActivity.this, "点击了第"+position+"个美眉 \nURL:"+mViewpager.getUrlList().get(position), Toast.LENGTH_SHORT).show();
            }
        });

Github 获取最新版本

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/185699.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • cms开源网站管理系统_javaweb开源商城

    cms开源网站管理系统_javaweb开源商城笔者整理了八款.Net优秀的开源CMS内容管理系统,推荐给广大的.net开发者。

  • 基于QT播放器的实现(一)Rgb、YUV格式(附带代码)

    基于QT播放器的实现(一)Rgb、YUV格式(附带代码)基于QT播放器的实现(一)Rgb、YUV格式色度空间转换YUV转RGB的公式对本地RGB32视频图像的播放色度空间转换YUV颜色模型其实常用于视频传输和图像压缩。由于人类的眼睛,对亮度的敏感度远超过对色彩的敏感度,所以视频传输过程中,为了减小带宽,通常将色彩分量UV的比例减小,以达到降低带宽的目的。这就出现了YUV4:4:4、YUV4:2:2、YUV4:1:1等格式。RGB32使用32位来…

  • CentOS镜像下载「建议收藏」

    CentOS镜像下载「建议收藏」CentOS6系统安装1、首先打开网易开源镜像站:http://mirrors.163.com/当然,大家也可以使用阿里开源镜像站:http://mirrors.aliyun.com/2、点击进入centos目录。3、因为我们选择安装centos6.5版本系统,所以点击进入6.5/目录4、我们打开里面的readme文件,找到下载地址:http://vault.cento…

  • Handler和HandlerThread

    Handler和HandlerThread

  • c++ map和set_STLset和map的区别

    c++ map和set_STLset和map的区别C++map和set的介绍及使用零、前言一、关联式容器二、键值对三、C++中的set1、set的介绍2、set的使用四、C++中的multiset五、C++中的map1、map的介绍2、map的使用六、C++中的multimap零、前言本章主要讲解C++中的关联式容器map和set的介绍及其使用一、关联式容器容器分类:序列式容器:初阶阶段中学习过STL中的部分容器,如:vector、list、deque等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身

  • 高德地图获取shp文件_手机高德地图坐标拾取

    高德地图获取shp文件_手机高德地图坐标拾取转载自:http://blog.csdn.net/yukimineryuu/article/details/50933582用Eclipse获取sha1值比较简单。最近自己换了androidstudio开发,申请key的时候,要两个版本的sha1值。一个是开发版(debug),一个是发布版(release)。debug版本的sha1比较好获取,网上有介绍,这里

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号