Android UI 元件 RecyclerView 多次初始化後空隙變大
最近在重構我的 Android App 程式碼,把 ListView 這個過時元件全改用 RecyclerView 代替。
發現某些地方的 RecyclerView 在經過多次資料重整(每次重整都會初始化一次)後,每個 item 中的空隙竟然變大了!!???
下面兩張圖是正常的樣子和經過多次重整的樣子(點擊右上角圖示可重整),可以看到每行的高度變高了,甚至分隔線的顏色還變黑......
發現某些地方的 RecyclerView 在經過多次資料重整(每次重整都會初始化一次)後,每個 item 中的空隙竟然變大了!!???
下面兩張圖是正常的樣子和經過多次重整的樣子(點擊右上角圖示可重整),可以看到每行的高度變高了,甚至分隔線的顏色還變黑......
開啟顯示版面配置界限後,可以看到每個 item 下緣都有多出一些空白
經過一番檢查後,發現問題出在這邊
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public void onTaskCompleted(RecyclerViewAdapter adapter) { | |
if (adapter.getItemCount() > 0) { | |
recyclerView.setAdapter(adapter); | |
recyclerView.setLayoutManager(new LinearLayoutManager(context)); | |
recyclerView.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); | |
} | |
} |
這段程式碼會在每次資料重整後設定 RecyclerView 一些 layout 狀態,其中這行正是問題的關鍵:
recyclerView.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));
只要把這行搬到 onCreate() 等地方讓它不要重複設定就可以解決問題!
不過基本上這個 RecyclerView 的 layout 並不會有其它變化,因此可以將這兩行一起搬走也不會有問題
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));
至於為什麼會有這種情況?分析了一下 RecyclerView 原始碼,可以看到 addItemDecoration 這個方法做的事就是將 ItemDecoration 加入一個 ArrayList。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void addItemDecoration(@NonNull RecyclerView.ItemDecoration decor) { | |
this.addItemDecoration(decor, -1); | |
} | |
public void addItemDecoration(@NonNull RecyclerView.ItemDecoration decor, int index) { | |
if (this.mLayout != null) { | |
this.mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll or layout"); | |
} | |
if (this.mItemDecorations.isEmpty()) { | |
this.setWillNotDraw(false); | |
} | |
if (index < 0) { | |
this.mItemDecorations.add(decor); | |
} else { | |
this.mItemDecorations.add(index, decor); | |
} | |
this.markItemDecorInsetsDirty(); | |
this.requestLayout(); | |
} |
mItemDecorations 是一個 ArrayList 物件
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final ArrayList<RecyclerView.ItemDecoration> mItemDecorations; |
然後在 onDraw() 方法中將它們全部繪出
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void onDraw(Canvas c) { | |
super.onDraw(c); | |
int count = this.mItemDecorations.size(); | |
for(int i = 0; i < count; ++i) { | |
((RecyclerView.ItemDecoration)this.mItemDecorations.get(i)).onDraw(c, this, this.mState); | |
} | |
} |
如此可以解釋為空白間隙是連續繪出 ItemDecoration 所疊加的結果。
留言
張貼留言