場景:同一 `Drawable` 實例 `setImageDrawable()` 給兩個 `ImageView`,調用 `drawable.mutate().setAlpha(50)` 期望兩者皆變透明,**實際只有第二個生效**。本文深度剖析 `Drawable.mutate()` 的「寫時複製」機制,揭示共用 Drawable 狀態共享的本質,給出正確解決方案。
Drawable drawable = getResources().getDrawable(R.drawable.ic_icon);
drawable.mutate().setAlpha(50); // 嘗試設置透明度
imageView1.setImageDrawable(drawable);
imageView2.setImageDrawable(drawable); // 只有 imageView2 變透明!
核心原因:
Drawable original = getResources().getDrawable(R.drawable.ic_icon);
// 方案一:mutate 一次,持有引用,多 View 共用該「可變副本」 (同步變化)
Drawable mutableShared = original.mutate();
mutableShared.setAlpha(50);
imageView1.setImageDrawable(mutableShared);
imageView2.setImageDrawable(mutableShared); // 兩者同步透明,後續修改 mutableShared 兩者聯動
// 方案二:各 View 獨立 mutate (獨立變化)
Drawable mutable1 = original.mutate();
mutable1.setAlpha(50);
imageView1.setImageDrawable(mutable1);
Drawable mutable2 = original.mutate();
mutable2.setAlpha(100); // 不同透明度
imageView2.setImageDrawable(mutable2);
若在點擊事件中:
imageView.setOnClickListener(v -> {
// 錯誤:每次點擊 mutate() 創建新副本,舊副本被 GC,View 仍持有舊引用 → 不生效
drawable.mutate().setAlpha(128);
// 正確:持有 View 當前 Drawable 引用並修改
Drawable current = imageView.getDrawable();
if (current != null) current.setAlpha(128); // 直接修改,無需 mutate (已是可變)
imageView.invalidate(); // 觸發重繪
});
**關鍵原則**:`mutate()` 是**創建副本**的工廠方法,**必須持有返回值**;View 已持有的 Drawable 直接修改屬性即可,無需再次 `mutate()`。
**`Drawable.mutate()` 返回新副本,不修改原對象。** 共用 Drawable 導致狀態同步,需 `mutate` 打破共享;但必須**持有返回的副本引用**並傳給 View。理解「ConstantState 共享 → mutate 打破共享 → 副本持有」的生命週期鏈條,即可精準控制每個 ImageView 的顯示狀態,避免「只有最後一個生效」的低級錯誤。