Android中按钮背景与Drawable资源匹配判断失效问题排查
解决Android中Drawable ConstantState比较不匹配的问题
嘿,我来帮你搞定这个头疼的问题!你代码里总是进else分支,核心原因是每次调用getResources().getDrawable(R.drawable.bg_default_note_button)都会生成一个全新的Drawable实例——哪怕是同一个资源ID,它的ConstantState对象也是不同的(看你日志里的@af66108和@760a287,这是两个不同的内存地址),用==直接比较内存地址肯定永远不相等。
给你几个实用的解决方案,按推荐程度排序:
方案一:用Tag标记按钮状态(最稳妥)
别纠结Drawable的实例比较了,直接给按钮加个状态标记才是最省心的方式。比如用setTag()记录当前背景的资源ID:
// 初始化按钮时,先设置初始状态标记 Button selectedButton = findViewById(R.id.your_button_id); selectedButton.setTag(R.drawable.bg_default_note_button); // 点击按钮的逻辑 public void onButtonClick(View view) { Button selectedButton = (Button) view; Integer currentBgId = (Integer) selectedButton.getTag(); if (currentBgId != null && currentBgId == R.drawable.bg_default_note_button) { // 切换为选中状态 selectedButton.setBackgroundResource(R.drawable.bg_selected_note_button); selectedButton.setTag(R.drawable.bg_selected_note_button); } else { // 这里可以切换回默认,或者做你需要的操作 selectedButton.setBackgroundResource(R.drawable.bg_default_note_button); selectedButton.setTag(R.drawable.bg_default_note_button); Log.d("State", "当前背景不是默认状态"); } }
这种方式完全绕开了Drawable实例的坑,逻辑清晰,还不容易出兼容问题。
方案二:提前缓存目标ConstantState
如果你一定要用ConstantState比较,记得提前缓存目标Drawable的状态,别每次都调用getDrawable生成新实例:
// 在Activity/Fragment的初始化阶段(比如onCreate)缓存 private Drawable.ConstantState defaultButtonState; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 一次性获取并缓存默认背景的ConstantState defaultButtonState = getResources().getDrawable(R.drawable.bg_default_note_button).getConstantState(); } // 点击逻辑 public void onButtonClick(View view) { Button selectedButton = (Button) view; // 用equals()比较,比==更可靠(不过缓存后其实==也能行,但equals更规范) if (selectedButton.getBackground().getConstantState().equals(defaultButtonState)) { selectedButton.setBackgroundResource(R.drawable.bg_selected_note_button); } else { Log.d("1", selectedButton.getBackground().getConstantState().toString()); Log.d("2", defaultButtonState.toString()); } }
这样你每次比较的都是同一个ConstantState实例,就不会出现不匹配的情况了。
方案三:比较Drawable的资源ID(API 21+)
从Android 5.0(API 21)开始,你可以尝试通过ConstantState的getResourceId()来比较资源本身,而不是实例:
public void onButtonClick(View view) { Button selectedButton = (Button) view; Drawable.ConstantState currentState = selectedButton.getBackground().getConstantState(); Drawable.ConstantState defaultState = getResources().getDrawable(R.drawable.bg_default_note_button, getTheme()).getConstantState(); // 注意:有些Drawable(比如复杂的StateListDrawable)可能返回0,这时候这个方法就失效了 if (currentState != null && defaultState != null && currentState.getResourceId() == defaultState.getResourceId()) { selectedButton.setBackgroundResource(R.drawable.bg_selected_note_button); } else { if (currentState != null) Log.d("1", currentState.toString() + " | ID: " + currentState.getResourceId()); if (defaultState != null) Log.d("2", defaultState.toString() + " | ID: " + defaultState.getResourceId()); } }
这个方法有局限性,不是所有Drawable都能正确返回资源ID,所以只推荐在简单场景下用。
内容的提问来源于stack exchange,提问作者Anthraxff
相关产品推荐
相关产品推荐

