zoukankan      html  css  js  c++  java
  • 自定义完美的ViewPager 真正无限循环的轮播图

           网上80%的思路关于Android轮播图无限循环都是不正确的,不是真正意义上的无限循环,

    其思路大多是将ViewPager的getCount方法返回值设置为Integer.MAX_VALUE,

    然后呢将ViewPager的当前展示页设置为第1000页或者是10000页,这样用户一般情况下是滑不到边界的

      例如有5张图片的轮播图,item的编号为(0,1,2,3,4)当前页的页号如果是5, 这时候就将编号设置为0,即 

    actPosition %= datas.size();这个公式就是这么来的

             这种思路实现的无限轮播虽然可以实现需求  但是却不是真正意义的无限轮播,结合了iOS 、HTML5的无限轮播图实现思路,总结如下:

       例如:有五张轮播图 item的编号为(0,1,2,3,4) 要想实现 无限循环  我们在这五张的头部和尾部各加一张即(5+2)张,item编号为(0,1,2,3,4,5,6)其中编号为0,6的两张不做展示只是为了做循环轮播的铺垫

         1、当我们从编号为5 右滑的时候到了编号6 这时候就将当前页面设置为1

         2、当我们从编号为1左滑的时候到了编号0  这时候就将当前页面设置为5

       第一种情况:

          第二种情况:

    这么做之后就可以实现无限轮播  怎么保证从编号6跳转编号1的时候不出现页面停顿 突然跳到下一页的现象呢?

    public Object instantiateItem (ViewGroup container, int position)

    在指定的位置创建页面;适配器负责添加view到这个容器中,然而它只保证在finishUpdate(ViewGroup)返回时才完成。

    public void destroyItem (ViewGroup container, int position, Object object)

    删除指定位置的页面;适配器负责从view容器中删除view,然而它只保证在finishUpdate(ViewGroup)返回时才完成。

     所以说 重点就在于finishUpdate(ViewGroup)这个方法 其实无论是创建view添加到容器中  还是 销毁view 都是在此方法结束之后执行的

    换句话说  就是 我在这个方法里让页面完成从 编号5跳转到编号1 或者从编号1跳转到编号5,此方法完成时 视图还未完成创建或者 销毁 这样也就不会出现 页面停顿 突然跳到下一页的现象

     @Override
            public void finishUpdate(ViewGroup container) {
                int position = mBanner.getCurrentItem();
                if (position == 0) {
                    position = datas.size();
                    viewPager.setCurrentItem(position,false);
                } else if (position == (datas.size()+2) - 1) {
                    position = 1;
                    viewPager.setCurrentItem(position,false);
                }
            }

    如此 完美解决 无限轮播

      一般情况下 轮播图要求自动轮播  没关系  我们可以利用Handler去开启线程 让其每隔一定时间去轮播 

    这里的重点是 如果我们定义每隔3秒轮播一张,当我们用手滑动了之后这时候要重新计时,防止用户刚滑动完 程序立马又滑动一次,

    handler.removeCallbacksAndMessages(null);
    此方法意思是移除所有的定消息 handler.sendEmptyMessageDelayed(
    0,3000);
    此方法是三秒之后发送一个 message.what=0的消息

    完整的代码

     我定义了一个View名字叫TopView 实现每隔3秒轮播,并且下方有小圆点(当前显示的编号小圆点会变成白色,其他小圆点显示为灰色)的轮播图

    基本思路是 在FrameLayout里边底层是一个Viewpager 上层是一个LinearLayout 里边有对应张数的小圆点 小圆点是根据数据的个数动态生成的

    类里边还定义了一个 点击监听接口 ,点击对应的图片可以回调给调用者

    public class TopView extends FrameLayout implements ViewPager.OnPageChangeListener {
        private ViewPager vPager;
        private List<ImageView> imgViews;
        private List<String> datas;// 数据源
    
        private LinearLayout navLayout;
        private LinearLayout.LayoutParams layoutParams;//线性布局中子控件使用的布局参数,作用设置子控件大小,外边距
        private Context mContext;
        private DownLoadImage imageLoader;
        private int currentPosition=0;
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                currentPosition = (++currentPosition) % imgViews.size();
                vPager.setCurrentItem(currentPosition,false);
    
                //处理完之前的消息之后再次发送一个3秒之后的消息  如此  可实现每隔三秒轮播
                if(handler!=null){
                    handler.sendEmptyMessageDelayed(0,3000);
                }
            }
        };
    
        public TopView(Context context) {
            this(context,null);
        }
    
        public TopView(Context context, AttributeSet attrs) {
            this(context,attrs,0);
        }
    
        public TopView(Context context,AttributeSet attrs,int defStyle) {
            super(context,attrs,defStyle);
            mContext=context;
            // 第二个参数this: 布局资源中根标签内声明的布局参数参考的父控件对象
            // 第三个参数true: 代表是将第一个参数中声明的子控件归属到第二个参数对象中,false不归属
            LayoutInflater.from(context).inflate(R.layout.topview, this, true);
            initView();
        }
    
        private void initView() {
            // 查找相关的UI控件
            vPager = (ViewPager) findViewById(R.id.viewPager);
            navLayout = (LinearLayout) findViewById(R.id.navLayout);
        }
    
        public void setData(List<String> datas) {
            this.datas = datas;
            createViews();
        }
    
        private void createViews() {
            // 根据数据源创建ViewPager中显示的UI
            imgViews = new ArrayList<ImageView>();//加入数据源
            layoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
            //  layoutParams.leftMargin=20;
            layoutParams.rightMargin=10;//px
            layoutParams.width=20;
            layoutParams.height=20;
            ImageView imgView = null;
            ImageView navImg = null;
            for (int i=0;i<datas.size();i++)
            {
                imgView = new ImageView(getContext());
                imgView.setScaleType(ImageView.ScaleType.FIT_XY);
                imgView.setTag(datas.get(i));
    
                imgViews.add(imgView);
    
                navImg = new ImageView(getContext());
                navImg.setScaleType(ImageView.ScaleType.CENTER_CROP);
                if(i==0)
                    navImg.setImageResource(R.drawable.page_now);
                else
                    navImg.setImageResource(R.drawable.page);
    
                //设置导航图片的标签: 当前导航图片的位置
                navImg.setTag(i);
    
                navImg.setLayoutParams(layoutParams);
                navLayout.addView(navImg);
            }
    
            vPager.setAdapter(new ImageAdapter());
            vPager.addOnPageChangeListener(this);
            loadImgs();
            //开启handler的线程 3秒之后发出此消息
            if(handler!=null){
                handler.sendEmptyMessageDelayed(0,3000);
            }
        }
    
        private void loadImgs() {
            // 加载网络图片加载后放入imageView
            for (int i=0;i<datas.size();i++) {
                String data=datas.get(i);
                for (ImageView imageView : imgViews) {
                    if(imageView.getTag().equals(data)){
                        getImageView(imageView,data,i);
                    }
                }
            }
        }
    
        class ImageAdapter extends PagerAdapter {
    
            @Override
            public int getCount() {
                return datas.size()+2;
            }
    
            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                // TODO Auto-generated method stub
                return arg0 == arg1;
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int actPosition) {
                //对Viewpager页号求模去除View列表中要显示的项
                actPosition %= datas.size();
                ImageView view = imgViews.get(actPosition);
                //如果View已经在之前添加到了一个父组件,则必须先remove,否则会抛出IllegalStateException。
                ViewParent viewParent = view.getParent();
                if (viewParent!=null){
                    ViewGroup parent = (ViewGroup)viewParent;
                    parent.removeView(view);
                }
                container.addView(view);
                return view;
            }
    
            @Override
            public void destroyItem(ViewGroup container, int actPosition, Object object) {
          //注意不在此方法进行removeView
            }
    
            @Override
            public void finishUpdate(ViewGroup container) {
                super.finishUpdate(container);
    
                int position = vPager.getCurrentItem();
                if (position == 0) {
                    position = datas.size();
                    currentPosition=position;
                    if(handler!=null){
                        handler.removeCallbacksAndMessages(null);
                        handler.sendEmptyMessageDelayed(0,3000);
                    }
                    vPager.setCurrentItem(position,false);
                } else if (position == (datas.size()+2) - 1) {
                    position = 1;
                    currentPosition=position;
                    if(handler!=null){
                        handler.removeCallbacksAndMessages(null);
                        handler.sendEmptyMessageDelayed(0,3000);
                    }
                    vPager.setCurrentItem(position,false);
                }
    
            }
    
        }
    
        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void onPageSelected(int position) {
            position=position % datas.size();
            if(handler!=null){
                handler.removeCallbacksAndMessages(null);
            }
            currentPosition=position;
            ImageView navImg  = null;
            //遍历 导航布局中所有的子控件,判断子控件的位置是否为选择位置,若是,则改变图片的内容
            for(int i=0;i<navLayout.getChildCount();i++){
                navImg = (ImageView) navLayout.getChildAt(i );//获取布局中指定位置的子控件
                if(i==position)
                    navImg.setImageResource(R.drawable.page_now);
                else
                    navImg.setImageResource(R.drawable.page);
            }
    
            if(handler!=null){
                handler.sendEmptyMessageDelayed(0,3000);
            }
    
        }
    
        public interface TopViewClickListener{
           public void onTopViewClick(int position);
        }
    
        public TopViewClickListener mTopViewClickListener;
        public void setTopViewClickListener(TopViewClickListener topViewClickListener){
            mTopViewClickListener=topViewClickListener;
        }
    
        private ImageView getImageView(ImageView imageView,String url, final int position) {
            imageView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mTopViewClickListener != null) {
                        mTopViewClickListener.onTopViewClick(position);
                    }
                }
            });
            if (imageLoader == null) {
                imageLoader = new DownLoadImage(mContext, R.drawable.bannerdefault, R.drawable.bannerdefault, null);
            }
            imageLoader.displayImage(url, imageView, null);
            return imageView;
        }
    
    
    
    }

     TopView类中用到的布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
    
        <android.support.v4.view.ViewPager
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    
        <LinearLayout
                android:id="@+id/navLayout"
                android:layout_height="30dp"
                android:layout_width="match_parent"
                android:layout_gravity="bottom"
                android:gravity="center"
                android:orientation="horizontal" />
    
    </FrameLayout>

    如何调用:

    在activity_main.xml中

     <com.myview.TopView
            android:id="@+id/topview"
            android:layout_width="match_parent"
            android:layout_height="@dimen/size_600px"/>

    在MainActivity 中的伪代码:

    private TopView topView;
    public class ActivityMain extends Activity implements TopView.TopViewClickListener{
    public void onCreate(。。。。。){
    //urls是图片的地址 topView.setData(urls); topView= (TopView) findViewById(R.id.topview); //设置点击图片事件的监听器 topView.setTopViewClickListener(this);   } @Override public void onTopViewClick(int position) { if (datas!= null && datas.size() > 0) { //用position去加载对应的数据即可 } } }

    如此  完美解决真正意义上的无限轮播图 

    严禁盗版    

    转载请注明出处:https://www.cnblogs.com/bimingcong/p/9028515.html

  • 相关阅读:
    Linux下编译LibCURL
    Linux下编译OpenSSL
    Linux下编译UnixODBC
    Linux下编译Boost
    MySQL存储引擎【InnoDB、MyISAM、Memory】
    MySQL数据库MyISAM和InnoDB存储引擎的比较
    MySQL存储引擎MyISAM与InnoDB的优劣
    14款经典的MySQL客户端软件
    MySQL 数据类型
    MySQL数据库的基本数据类型
  • 原文地址:https://www.cnblogs.com/bimingcong/p/9028515.html
Copyright © 2011-2022 走看看