RecyclerView实现优雅的瀑布流图片加载

开篇


这是我在上写的第一篇博客。非常喜欢的风格,所以想在这里写下我Android之路所遇到的一些麻烦,和我如何解决这一问题。

之前一直使用ListView和GridView来应用在开发中,但是一直仰慕RecyclerView的大名,故开始踏上了RecyclerView的使用之旅。在使用过程中是遇到了很多的坑,比如说给RecyclerView 加上事件监听,我直接在RecyclerView上add了一个监听事件,可是程序运行之后却发现并没有事件回调出来。。。后来才知道RecyclerView并没有提供相应的接口,比如ClickListener和LongClickListener。我不明白为什么谷歌为什么这么做,可能是为了让他更能专注于他的技能Recycler吧。
  好了接下来是正题,大家都知道开发中我们常常使用RecyclerView实现三种布局管理,分别是LinearLayoutManager、GridLayoutManager和StaggeredGridLayoutManager,前两种一般是没什么太大问题,今天我们来说说第三种瀑布流的实现方式。

*这是我们最基础的用法,添加瀑布流3列垂直分布

StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager );
adapter = new MyRecyclerAdapter();
recyclerView.setAdapter(adapter);

这里我根据图片数量给他设置一些随机高度,因为我使用的接口并没有返回图片的宽高

List heights = new ArrayList<>();
for (int i = 0; i < urls.size(); i++) {
  int x=random.nextInt(200) + 200;
  heights.add(x);
}

并在onBindViewHolder中设置itemView的高度

StaggeredGridLayoutManager.LayoutParams layoutParams =
(StaggeredGridLayoutManager.LayoutParams) itemView.getLayoutParams();
layoutParams.height = heights.get(position);
itemView.setLayoutParams(layoutParams);
我放入了一些测试数据,并使用了Picasso加载图片

我们发现被滑出屏幕的图片又消失被重新加载了

这是什么原因呢

给bindView打上日志,发现itemView一旦划入可见区域,便会调用onBindViewHolder方法...于是Picasso又给我们的图片重新加载了一遍

这里我的思路是:

  • 设置ImageView的tag,可以设置tag为position或者url。
  • 在加载图片的时候先进行判断是否有tag,没有tag进行图片加载
        @Override
        public void onBindViewHolder(MyRecyclerViewHolder holder, final int position) {
            if (holder.itemView.getTag() == null) {
                holder.itemView.setTag(position);
                holder.bind(position);
            }
        }

这样就不会重复加载了,不知道是否有更加合理的方式,有请告知,感激不尽。

接下来我们的效果是

autoChangeItem.gif

这里的问题可愁了我了……
网上查了好久都没有发现好的文章能真正帮我解决这个问题
最终放弃寻求别人帮助,还是靠自己解决吧。。。
我决定对RecyclerView的Adapter进行拆解,对他的各种可能需要用到的方法进行日志打印,我相信create和bind方法两个肯定是打上了日志,最终我发现每次itemView自动交换位置的时候,onCreateViewHolder这个方法就会被调用。哪里有问题点哪里。。。我们来看一下源码中,对onCreateViewHolder的描述,我截取了最为重要的部分

* @param parent The ViewGroup into which the new View will be added after it is bound to
*               an adapter position.
* @param viewType The view type of the new View.
*
* @return A new ViewHolder that holds a View of the given view type.
* @see #getItemViewType(int)
* @see #onBindViewHolder(ViewHolder, int)

可见RecyclerView真的很灵活,他根据你返回的View类型来决定create一个新的视图的类型,我想问题出在这里,默认返回的是0,当我从下往上滑到最顶部的时候,复用的View大小是根据下面的itemView的大小,所以高度上出现了不适应,layoutManager会自动调整位置,于是出现了上述情况

我们重写getItemViewType方法,让我们的高度成为type的值

@Override
public int getItemViewType(int position) {
     return heights.get(position);
//   return super.getItemViewType(position);
}

OK,我们进行一下测试。


last.gif

至此我们实现了瀑布流图片加载

  但是还不够优雅,因为我相信,我在这里使用图片的高度作为ViewType肯定是有问题的,因我的图片高度太多不固定的值,有的是重复的,但是大多数是不重复的,这势必会造成性能问题。所以建议在使用瀑布流的时候,不要用太多不同的高度,适度就行。。。一般是根据图片的大小来计算。

当然具体情况还是得具体对待……

结束语:我对于网上某些写的RecyclerView的文章还是要说一句,多一些真诚,少一些CV。
文章中如有什么错误,请您谅解并且可以给我留言指出,写了好久,休息休息。Thanks!

你可能感兴趣的:(RecyclerView实现优雅的瀑布流图片加载)