开篇
这是我在简书上写的第一篇博客。非常喜欢简书的风格,所以想在这里写下我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!
网友评论