AppCompatCompoundButtonHelper.java revision 091b0f935e68ce9bfecc2422e60eada33fa3b09c
1091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes/* 2091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Copyright (C) 2015 The Android Open Source Project 3091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * 4091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * you may not use this file except in compliance with the License. 6091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * You may obtain a copy of the License at 7091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * 8091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * http://www.apache.org/licenses/LICENSE-2.0 9091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * 10091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Unless required by applicable law or agreed to in writing, software 11091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * See the License for the specific language governing permissions and 14091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * limitations under the License. 15091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes */ 16091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 17091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banespackage android.support.v7.widget; 18091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 19091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.content.res.ColorStateList; 20091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.content.res.TypedArray; 21091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.graphics.PorterDuff; 22091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.graphics.drawable.Drawable; 23091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.os.Build; 24091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.annotation.Nullable; 25091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 26091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v4.widget.CompoundButtonCompat; 27091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v7.appcompat.R; 28091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v7.graphics.drawable.DrawableUtils; 29091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v7.internal.widget.TintManager; 30091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.util.AttributeSet; 31091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.widget.CompoundButton; 32091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 33091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesclass AppCompatCompoundButtonHelper { 34091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 35091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private final CompoundButton mView; 36091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private final TintManager mTintManager; 37091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 38091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private ColorStateList mButtonTintList = null; 39091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private PorterDuff.Mode mButtonTintMode = null; 40091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private boolean mHasButtonTint = false; 41091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private boolean mHasButtonTintMode = false; 42091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 43091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private boolean mSkipNextApply; 44091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 45091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes /** 46091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Interface which allows us to directly set a button, bypass any calls back to ourselves. 47091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes */ 48091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes interface DirectSetButtonDrawableInterface { 49091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void setButtonDrawable(Drawable buttonDrawable); 50091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 51091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 52091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager) { 53091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mView = view; 54091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mTintManager = tintManager; 55091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 56091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 57091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { 58091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton, 59091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes defStyleAttr, 0); 60091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes try { 61091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (a.hasValue(R.styleable.CompoundButton_android_button)) { 62091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes final int resourceId = a.getResourceId( 63091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes R.styleable.CompoundButton_android_button, 0); 64091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (resourceId != 0) { 65091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mView.setButtonDrawable(mTintManager.getDrawable(resourceId)); 66091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 67091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 68091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (a.hasValue(R.styleable.CompoundButton_buttonTint)) { 69091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes CompoundButtonCompat.setButtonTintList(mView, 70091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes a.getColorStateList(R.styleable.CompoundButton_buttonTint)); 71091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 72091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) { 73091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes CompoundButtonCompat.setButtonTintMode(mView, 74091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes DrawableUtils.parseTintMode( 75091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes a.getInt(R.styleable.CompoundButton_buttonTintMode, -1), 76091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes null)); 77091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 78091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } finally { 79091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes a.recycle(); 80091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 81091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 82091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 83091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void setSupportButtonTintList(ColorStateList tint) { 84091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mButtonTintList = tint; 85091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mHasButtonTint = true; 86091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 87091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes applyButtonTint(); 88091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 89091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 90091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes ColorStateList getSupportButtonTintList() { 91091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes return mButtonTintList; 92091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 93091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 94091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) { 95091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mButtonTintMode = tintMode; 96091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mHasButtonTintMode = true; 97091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 98091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes applyButtonTint(); 99091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 100091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 101091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes PorterDuff.Mode getSupportButtonTintMode() { 102091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes return mButtonTintMode; 103091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 104091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 105091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void onSetButtonDrawable() { 106091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mSkipNextApply) { 107091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mSkipNextApply = false; 108091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes return; 109091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 110091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 111091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mSkipNextApply = true; 112091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes applyButtonTint(); 113091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 114091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 115091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void applyButtonTint() { 116091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView); 117091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 118091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (buttonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) { 119091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes buttonDrawable = DrawableCompat.wrap(buttonDrawable); 120091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes buttonDrawable = buttonDrawable.mutate(); 121091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mHasButtonTint) { 122091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes DrawableCompat.setTintList(buttonDrawable, mButtonTintList); 123091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 124091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mHasButtonTintMode) { 125091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes DrawableCompat.setTintMode(buttonDrawable, mButtonTintMode); 126091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 127091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes // The drawable (or one of its children) may not have been 128091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes // stateful before applying the tint, so let's try again. 129091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (buttonDrawable.isStateful()) { 130091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes buttonDrawable.setState(mView.getDrawableState()); 131091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 132091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mView.setButtonDrawable(buttonDrawable); 133091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 134091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 135091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 136091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes int getCompoundPaddingLeft(int superValue) { 137091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 138091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll 139091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes // workaround that here 140091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView); 141091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (buttonDrawable != null) { 142091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes superValue += buttonDrawable.getIntrinsicWidth(); 143091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 144091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 145091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes return superValue; 146091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 147091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes} 148