美文网首页优秀案例自定义控件
RecyclerView实现优雅的瀑布流图片加载

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

作者: Nxiao | 来源:发表于2017-03-26 23:44 被阅读0次

    开篇


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

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

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

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

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

    List<Integer> 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加载图片

    <img src="https://img.haomeiwen.com/i2826360/0485125ee3747b15.gif?imageMogr2/auto-orient/strip" style="zoom:50%"/>

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

    这是什么原因呢

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

    这里我的思路是:

    • 设置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)
    

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

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

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

    OK,我们进行一下测试。


    last.gif

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

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

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

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

    相关文章

      网友评论

        本文标题:RecyclerView实现优雅的瀑布流图片加载

        本文链接:https://www.haomeiwen.com/subject/maxkottx.html