Android UI 元件 RecyclerView 多次初始化後空隙變大

最近在重構我的 Android App 程式碼,把 ListView 這個過時元件全改用 RecyclerView 代替。
發現某些地方的 RecyclerView 在經過多次資料重整(每次重整都會初始化一次)後,每個 item 中的空隙竟然變大了!!???

下面兩張圖是正常的樣子和經過多次重整的樣子(點擊右上角圖示可重整),可以看到每行的高度變高了,甚至分隔線的顏色還變黑......


開啟顯示版面配置界限後,可以看到每個 item 下緣都有多出一些空白


經過一番檢查後,發現問題出在這邊

@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));
}
}
view raw Activity.java hosted with ❤ by GitHub
這段程式碼會在每次資料重整後設定 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。

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 物件

final ArrayList<RecyclerView.ItemDecoration> mItemDecorations;
然後在 onDraw() 方法中將它們全部繪出

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 所疊加的結果。

留言

這個網誌中的熱門文章

Android 藍牙連接通訊實作心得

在 Android 上自訂 Zxing 掃描框樣式與大小位置