1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.support.v7.widget; 18 19 import android.content.res.ColorStateList; 20 import android.content.res.TypedArray; 21 import android.graphics.PorterDuff; 22 import android.graphics.drawable.Drawable; 23 import android.os.Build; 24 import android.support.annotation.Nullable; 25 import android.support.v4.graphics.drawable.DrawableCompat; 26 import android.support.v4.widget.CompoundButtonCompat; 27 import android.support.v7.appcompat.R; 28 import android.support.v7.graphics.drawable.DrawableUtils; 29 import android.support.v7.internal.widget.TintManager; 30 import android.util.AttributeSet; 31 import android.widget.CompoundButton; 32 33 class AppCompatCompoundButtonHelper { 34 35 private final CompoundButton mView; 36 private final TintManager mTintManager; 37 38 private ColorStateList mButtonTintList = null; 39 private PorterDuff.Mode mButtonTintMode = null; 40 private boolean mHasButtonTint = false; 41 private boolean mHasButtonTintMode = false; 42 43 private boolean mSkipNextApply; 44 45 /** 46 * Interface which allows us to directly set a button, bypass any calls back to ourselves. 47 */ 48 interface DirectSetButtonDrawableInterface { setButtonDrawable(Drawable buttonDrawable)49 void setButtonDrawable(Drawable buttonDrawable); 50 } 51 AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager)52 AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager) { 53 mView = view; 54 mTintManager = tintManager; 55 } 56 loadFromAttributes(AttributeSet attrs, int defStyleAttr)57 void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { 58 TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton, 59 defStyleAttr, 0); 60 try { 61 if (a.hasValue(R.styleable.CompoundButton_android_button)) { 62 final int resourceId = a.getResourceId( 63 R.styleable.CompoundButton_android_button, 0); 64 if (resourceId != 0) { 65 mView.setButtonDrawable(mTintManager.getDrawable(resourceId)); 66 } 67 } 68 if (a.hasValue(R.styleable.CompoundButton_buttonTint)) { 69 CompoundButtonCompat.setButtonTintList(mView, 70 a.getColorStateList(R.styleable.CompoundButton_buttonTint)); 71 } 72 if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) { 73 CompoundButtonCompat.setButtonTintMode(mView, 74 DrawableUtils.parseTintMode( 75 a.getInt(R.styleable.CompoundButton_buttonTintMode, -1), 76 null)); 77 } 78 } finally { 79 a.recycle(); 80 } 81 } 82 setSupportButtonTintList(ColorStateList tint)83 void setSupportButtonTintList(ColorStateList tint) { 84 mButtonTintList = tint; 85 mHasButtonTint = true; 86 87 applyButtonTint(); 88 } 89 getSupportButtonTintList()90 ColorStateList getSupportButtonTintList() { 91 return mButtonTintList; 92 } 93 setSupportButtonTintMode(@ullable PorterDuff.Mode tintMode)94 void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) { 95 mButtonTintMode = tintMode; 96 mHasButtonTintMode = true; 97 98 applyButtonTint(); 99 } 100 getSupportButtonTintMode()101 PorterDuff.Mode getSupportButtonTintMode() { 102 return mButtonTintMode; 103 } 104 onSetButtonDrawable()105 void onSetButtonDrawable() { 106 if (mSkipNextApply) { 107 mSkipNextApply = false; 108 return; 109 } 110 111 mSkipNextApply = true; 112 applyButtonTint(); 113 } 114 applyButtonTint()115 void applyButtonTint() { 116 Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView); 117 118 if (buttonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) { 119 buttonDrawable = DrawableCompat.wrap(buttonDrawable); 120 buttonDrawable = buttonDrawable.mutate(); 121 if (mHasButtonTint) { 122 DrawableCompat.setTintList(buttonDrawable, mButtonTintList); 123 } 124 if (mHasButtonTintMode) { 125 DrawableCompat.setTintMode(buttonDrawable, mButtonTintMode); 126 } 127 // The drawable (or one of its children) may not have been 128 // stateful before applying the tint, so let's try again. 129 if (buttonDrawable.isStateful()) { 130 buttonDrawable.setState(mView.getDrawableState()); 131 } 132 mView.setButtonDrawable(buttonDrawable); 133 } 134 } 135 getCompoundPaddingLeft(int superValue)136 int getCompoundPaddingLeft(int superValue) { 137 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 138 // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll 139 // workaround that here 140 Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView); 141 if (buttonDrawable != null) { 142 superValue += buttonDrawable.getIntrinsicWidth(); 143 } 144 } 145 return superValue; 146 } 147 } 148