- Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_launcher);
- drawable.setColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP);
- StateListDrawable stateListDrawable = new StateListDrawable();
- stateListDrawable.addState(new int[]{}, drawable);
- setBackground(stateListDrawable);
- 解説
原因は DrawableContainer の selectDrawable() での処理です。 5.0 から ColorFilter や tint を考慮するようになり、state に対応する Drawable に明示的に ColorFilter や tint をセットするようになりました。
4.4.0 の DrawableContainer.selectDrawable()
- 306 public boolean selectDrawable(int idx) {
- 336 if (d != null) {
- 337 d.mutate();
- 338 if (mDrawableContainerState.mEnterFadeDuration > 0) {
- 339 mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
- 340 } else {
- 341 d.setAlpha(mAlpha);
- 342 }
- 343 d.setVisible(isVisible(), true);
- 344 d.setDither(mDrawableContainerState.mDither);
- 345 d.setColorFilter(mColorFilter);
- 346 d.setState(getState());
- 347 d.setLevel(getLevel());
- 348 d.setBounds(getBounds());
- 349 d.setLayoutDirection(getLayoutDirection());
- 350 d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
- 351 }
- 412 public boolean selectDrawable(int idx) {
- 442 if (d != null) {
- 443 d.mutate();
- 444 if (mDrawableContainerState.mEnterFadeDuration > 0) {
- 445 mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
- 446 } else if (mHasAlpha) {
- 447 d.setAlpha(mAlpha);
- 448 }
- 449 if (mDrawableContainerState.mHasColorFilter) {
- 450 // Color filter always overrides tint.
- 451 d.setColorFilter(mDrawableContainerState.mColorFilter);
- 452 } else {
- 453 if (mDrawableContainerState.mHasTintList) {
- 454 d.setTintList(mDrawableContainerState.mTintList);
- 455 }
- 456 if (mDrawableContainerState.mHasTintMode) {
- 457 d.setTintMode(mDrawableContainerState.mTintMode);
- 458 }
- 459 }
- 460 d.setVisible(isVisible(), true);
- 461 d.setDither(mDrawableContainerState.mDither);
- 462 d.setState(getState());
- 463 d.setLevel(getLevel());
- 464 d.setBounds(getBounds());
- 465 d.setLayoutDirection(getLayoutDirection());
- 466 d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
- 5.0 未満でどうするか
以下のコードでは、デフォルト用の Drawable からタップしたとき用の ColorFilter がかかった Drawable を用意し、StateListDrawable を構成して背景にセットしています。 このコードを 5.0 以降で実行すると思ったように動きますが、5.0 未満だとタップしたときに色が変わりません。
- Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_launcher);
- Drawable pressedDrawable = drawable.getConstantState().newDrawable().mutate();
- pressedDrawable.setColorFilter(pressedColor, PorterDuff.Mode.SRC_ATOP);
- StateListDrawable stateListDrawable = new StateListDrawable();
- stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
- stateListDrawable.addState(new int[]{}, drawable);
- setBackground(stateListDrawable);
- private static class PressedStateListDrawable extends StateListDrawable {
- private final int pressedColor;
- public PressedStateListDrawable(Drawable drawable, int pressedColor) {
- super();
- this.pressedColor = pressedColor;
- addState(new int[]{android.R.attr.state_pressed}, drawable);
- addState(new int[]{}, drawable);
- }
- @Override
- protected boolean onStateChange(int[] states) {
- boolean isPressed = false;
- for (int state : states) {
- if (state == android.R.attr.state_pressed) {
- isPressed = true;
- break;
- }
- }
- if (isPressed) {
- setColorFilter(pressedColor, PorterDuff.Mode.SRC_ATOP);
- } else {
- clearColorFilter();
- }
- return super.onStateChange(states);
- }
- @Override
- public boolean isStateful() {
- return true;
- }
- }
- setBackground(new PressedStateListDrawable(drawable, pressedColor));