美文网首页程序员
轮播图优化-实现子view的复用

轮播图优化-实现子view的复用

作者: 牟乘风 | 来源:发表于2018-05-22 17:13 被阅读37次

轮播图控件刚毕业的同学们就会写了,这里简单介绍下自己在做RN轮播图时一些心得:

  • 回收与复用弃用的子view,至多只会存在有3个子View的实例。
  • 手动滑动与自动播放的优雅处理,不重写onTouchEvent。
  • 使用fresco的SimpleDraweeView作为子View加载网络图片,管理图片缓存
  • 循环轮播,播放到最后一张图时,下一张为第一张图

1. 回收与复用弃用的子view

申明一个list来存储弃用的子view。 2.png 实际上,只会有一个弃用的view,所以这里直接使用一个view变量也可以 2.png 然后复写PagerAdapter中如下两个方法 3.png 4.png 在instantiateItem方法中,我们在没有弃用的子view时创建子view,而有弃用的子view时,就直接使用该弃用的子view来加载网络图片(和ListAdapter中getView()是不是很像?)。在destroyItem时,参数object即是被弃用的子view,我们回收到unusedList中。

2. 手动滑动与自动播放的优雅处理

一般轮播图都支持手动滑动,在手动滑动式是应当禁止自动播放的,我发现同学们第一想到的解决方案是复写view的onTouchEvent()方法,在ACTION_DOWN时禁止自动播放,在ACTION_UP时恢复自动播放,当然这个方案无可厚非,只不过可能需要考虑touchEvent的各种事件而不仅仅是down和up,且是否要消费touch事件很多人处理的不一样,我介绍下另一种通过处理OnPageChangeListener中的onPageScrollStateChanged()方法来实现该功能的方法 5.png 当状态为空闲时恢复自动播放,当状态为另外两个时(拖拽和滑动)禁止自动播放。由于自动播放和手动滑动都会触发这个方法,自动播放时,state从2->0,手动滑动时state从1->2->0。所以通过这样的处理,既实现了自动播放也解决了手动滑动时禁止自动播放的问题,这里runnable的实现如下 6.png

3. 使用fresco的SimpleDraweeView作为子View

呃,fresco的SimpleDraweeView继承与ImageView,可以帮助我们处理下载网络图片的功能,还可以自动管理图片缓存,是一个非常棒的网络图像控件,推荐给大家,具体用法在图3中。另外在使用SimpleDraweeView前,一定不要忘记了调用 7.png

4. 循环轮播

相信这个功能的实现同学们的都耳熟能详,我和大家并无二样,一来凑个数,二来方便新人了解

首先getCount返回一个特大值 8.png ,然后在图3中设置url时取position对urls总数的模数 9.png

然后就没有了

完整代码如下

public class TurnPlayer extends FrameLayout implements ViewPager.OnPageChangeListener {
    private ViewPager mViewPager;
    private String[] mUrls;
    private List<SimpleDraweeView> unusedList = new ArrayList<>();
    private int delay = 2000; // 默认轮播时间

    final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (getContext() != null) {
                int currentItem = mViewPager.getCurrentItem();
                mViewPager.setCurrentItem(currentItem + 1, true);
                postDelayed(runnable, delay);
            }
        }
    };

    public TurnPlayer(@NonNull Context context) {
        super(context);
        init(context);
    }

    public TurnPlayer(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public TurnPlayer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mViewPager = new ViewPager(context);
        mViewPager.setAdapter(new TurnPlayerAdapter());
        mViewPager.addOnPageChangeListener(this);
        addView(mViewPager);

        Fresco.initialize(context);
    }

    void setDelay(int delay) {
        this.delay = delay;
    }

    void setData(String... urls) {
        mUrls = urls;
        mViewPager.getAdapter().notifyDataSetChanged();
        postDelayed(runnable, delay);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            postDelayed(runnable, delay);//恢复自动播放
        } else {
            removeCallbacks(runnable);//禁止自动播放
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        postDelayed(runnable, delay);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeCallbacks(runnable);
    }

    private class TurnPlayerAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return mUrls == null ? 0 : (mUrls.length > 1 ? Integer.MAX_VALUE : mUrls.length);
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            SimpleDraweeView view;
            if (unusedList.isEmpty()) {
                view = new SimpleDraweeView(container.getContext());
                view.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.CENTER_INSIDE);
            } else {
                view = unusedList.remove(0);
            }
            view.setController(Fresco.newDraweeControllerBuilder()
                    .setUri(Uri.parse(mUrls[position % mUrls.length]))
                    .setAutoPlayAnimations(true)
                    .build());
            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
            unusedList.add((SimpleDraweeView) object);
        }
    }
}

相关文章