Android——viewPager使用小结

  1. viewpager的简单使用

    如果使用viewpager来实现fragment的左右滑动的话,那么直接继承FragmentStatePagerAdapter或FragmentPagerAdapter重写其方法即可

    (FragmentStatePagerAdapter:在不需要的时候会销毁fragment实例,一般用于大量数据zaifragment上显示的场景;FragmentPagerAdapter:在不需要的时候只会销毁fragment的视图,不会销毁fragment的实例,一般用于只有少量fragment但需要频繁切换的场景)

    但如果想实现非fragment的滑动则需要重写原生的pagerAdapter,并且实现其中的四个方法:

    方法

    作用

    getCount()

    adapter中数据的数量

    isViewFromObject(@NonNull View view, @NonNull Object object)

    用来判断instantiateItem函数返回的值和当前view是否对应

    *viewpager不直接处理每一个视图而是将各个视图与一个键联系起来。这个键用来跟踪且唯一代表一个页面(当然这个方法中可以直接返回视图本身,用视图本身做键,并且在instantiateItem方法里返回该page本身)

    instantiateItem(@NonNull ViewGroup container, int position)

    为给定的位置创建pager视图

    destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object)

    删除指定位置中的pager视图

    之后在viewpager实例中setAdapter()即可实现一个简单的viewpager。

    加载当前页面时会把前后页面都加载好,作为过度页面,并且遍历其他页面将其删除。可以通过setOffscreenPageLimit(int)方法定制预加载页面的数量.

  2. viewpager实现无限轮播

    实现轮播其实很简单只要用handler的延迟发送消息即可

    private final Runnable mLoopRunnable = new Runnable() {
        @Override
        public void run() {
                currentPosition1 = viewPager1.getCurrentItem();
                currentPosition1++;
                //设置下一个page是当前
                viewPager1.setCurrentItem(currentPosition1, false);
                //此处适当加一下下一页面的处理逻辑
                。。。
                //循环发消息
                 mHandler.postDelayed(this, mDelayedTime);
        }
    };
    

    然而要实现无限轮播,网上普遍的有两种方式

  • 第一种是将pagerAdapter大小设置成Integer.MAX_VALUE并将起始位置设置成Integer.MAX_VALUE的中间

    //当前选中页
    private int currentPosition;
    //数据项个数
    private List<Integer> itemList;
    
    public static final int mLooperCount = 500;
    
    
    //设置当前选中的item
    currentPosition = getStartItem();
    viewPager1.setCurrentItem(currentPosition1);
    
    private int getStartItem() {
        if(getRealCount() == 0){
                return 0;
            }
        // 我们设置当前选中的位置为Integer.MAX_VALUE / 2,这样开始就能往左滑动
        // 但是要保证这个值与getRealPosition 的 余数为0,因为要从第一页开始显示
        int currentItem =BannerAdapter.mLooperCount / 2;
        if(currentItem % getRealCount()  ==0 ){
            return currentItem;
        }
        // 直到找到从0开始的位置
        while (currentItem % getRealCount() != 0){
            currentItem++;
        }
        return currentItem;
    }
    
    //获取数据项个数
    private int getRealCount() {
        return itemList == null ? 0 : itemList.size();
    }
    
    public int getCount() {
        return Integer.MAX_VALUE;
    }
    代码抄自网络,但反正实现大致就是这个样子

  • 第二种是在页面前后分别添加最后一页和第一页的数据,并且当滑到0和最后一页的时候默默的将页面切到倒数第二页和第一页

    具体实现可参考:ViewPager两种方式实现无限轮播 - 掘金

    推荐第二种,第一种可能会出现白屏甚至anr。

3. viewPager数据更新时无限轮播的坑

数据更新有两种方法,但都需要进行相应的封装:

  • 每次有新数据来都重新setAdapter()

    正常使用这个方法其实是没有问题的,但是当想实现无限轮播效果的时候,setAdapter会出现白屏闪烁的现象,甚至会出现anr。

    白屏和anr都是因为轮播的技术选型选择了无限大的那个方法才会出现的,但是无论选择那个方法数据刷新都会有闪烁。

    怀疑是populate()方法绘制图片的问题

    若要避免白屏和anr可参考此链接进行修改ViewPager anr,页面空白问题完全解析 - 简书(但其实并不推荐此方法)

  • 有数据来之后,更新PagerAdapter中的数据,并且调用adapter的notifyDataSetChanged()方法

    notifyDataSetChanged()方法最终调用dataSetChanged()方法,而在这个方法中,判断item是否替换掉是根据一个position标签位进行判断的,而获得这个标签位的方法在mAdapter.getItemPosition(ii.object)中

    然而这个getItemPosition()方法是固定返回POSITION_UNCHANGED也就是-1,也就是说靠原先的方法永远也不会更新数据。那么我们的做法就是重写这个getItemPosition方法,使其在合适的时机返回合适的值。

    此处是事先在view中设置tag,将位置与判断条件都存起来,在 getItemPosition()方法中将其取出作为判断两个view的内容是否一致的条件,返回对应的标签位。

    存tag的时机应该放在初始化view的地方,即instantiateItem()中。

     @Override
        public Object instantiateItem(ViewGroup container, int position) {
           。。。
            View view = initView(pos);
            view.setTag(bannerItems.get(pos).getImageUrl());
            view.setTag(R.string.tag_position_key, pos);
           。。。
            container.addView(view, params);
            return view;
        }

    @Override
        public int getItemPosition(Object object) {
            if (object instanceof View){
                View view = (View) object;
                String imageUrl = (String) view.getTag();
                int position = (int) view.getTag(R.string.tag_position_key);
                int b = imageUrl.equals(bannerItems.get(position).getImageUrl()) ? POSITION_UNCHANGED : POSITION_NONE;
                return b;
            }
            return super.getItemPosition(object);
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值