轮播图控件刚毕业的同学们就会写了,这里简单介绍下自己在做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. 循环轮播
相信这个功能的实现同学们的都耳熟能详,我和大家并无二样,一来凑个数,二来方便新人了解
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);
}
}
}














网友评论