開篇
這是我在簡書上寫的第一篇博客。非常喜歡簡書的風格,所以想在這里寫下我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="http://upload-images.jianshu.io/upload_images/2826360-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);
}
}
這樣就不會重復加載了,不知道是否有更加合理的方式,有請告知,感激不盡。
接下來我們的效果是
這里的問題可愁了我了……
網上查了好久都沒有發現好的文章能真正幫我解決這個問題
最終放棄尋求別人幫助,還是靠自己解決吧。。。
我決定對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,我們進行一下測試。
至此我們實現了瀑布流圖片加載
??但是還不夠優雅,因為我相信,我在這里使用圖片的高度作為ViewType肯定是有問題的,因我的圖片高度太多不固定的值,有的是重復的,但是大多數是不重復的,這勢必會造成性能問題。所以建議在使用瀑布流的時候,不要用太多不同的高度,適度就行。。。一般是根據圖片的大小來計算。
當然具體情況還是得具體對待……
結束語:我對于網上某些寫的RecyclerView的文章還是要說一句,多一些真誠,少一些CV。
文章中如有什么錯誤,請您諒解并且可以給我留言指出,寫了好久,休息休息。Thanks!