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 androidx.appcompat.widget; 18 19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 20 21 import android.content.Context; 22 import android.content.res.ColorStateList; 23 import android.graphics.Bitmap; 24 import android.graphics.PorterDuff; 25 import android.graphics.drawable.Drawable; 26 import android.net.Uri; 27 import android.util.AttributeSet; 28 import android.widget.ImageButton; 29 import android.widget.ImageView; 30 31 import androidx.annotation.DrawableRes; 32 import androidx.annotation.Nullable; 33 import androidx.annotation.RestrictTo; 34 import androidx.appcompat.R; 35 import androidx.core.view.TintableBackgroundView; 36 import androidx.core.widget.ImageViewCompat; 37 import androidx.core.widget.TintableImageSourceView; 38 39 /** 40 * A {@link ImageButton} which supports compatible features on older versions of the platform, 41 * including: 42 * <ul> 43 * <li>Allows dynamic tint of its background via the background tint methods in 44 * {@link androidx.core.view.ViewCompat}.</li> 45 * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and 46 * {@link R.attr#backgroundTintMode}.</li> 47 * <li>Allows dynamic tint of its image via the image tint methods in 48 * {@link ImageViewCompat}.</li> 49 * <li>Allows setting of the image tint using {@link R.attr#tint} and 50 * {@link R.attr#tintMode}.</li> 51 * </ul> 52 * 53 * <p>This will automatically be used when you use {@link ImageButton} in your layouts 54 * and the top-level activity / dialog is provided by 55 * <a href="{@docRoot}topic/libraries/support-library/packages.html#v7-appcompat">appcompat</a>. 56 * You should only need to manually use this class when writing custom views.</p> 57 */ 58 public class AppCompatImageButton extends ImageButton implements TintableBackgroundView, 59 TintableImageSourceView { 60 61 private final AppCompatBackgroundHelper mBackgroundTintHelper; 62 private final AppCompatImageHelper mImageHelper; 63 AppCompatImageButton(Context context)64 public AppCompatImageButton(Context context) { 65 this(context, null); 66 } 67 AppCompatImageButton(Context context, AttributeSet attrs)68 public AppCompatImageButton(Context context, AttributeSet attrs) { 69 this(context, attrs, R.attr.imageButtonStyle); 70 } 71 AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr)72 public AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr) { 73 super(TintContextWrapper.wrap(context), attrs, defStyleAttr); 74 75 mBackgroundTintHelper = new AppCompatBackgroundHelper(this); 76 mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); 77 78 mImageHelper = new AppCompatImageHelper(this); 79 mImageHelper.loadFromAttributes(attrs, defStyleAttr); 80 } 81 82 @Override setImageResource(@rawableRes int resId)83 public void setImageResource(@DrawableRes int resId) { 84 // Intercept this call and instead retrieve the Drawable via the image helper 85 mImageHelper.setImageResource(resId); 86 } 87 88 @Override setImageDrawable(@ullable Drawable drawable)89 public void setImageDrawable(@Nullable Drawable drawable) { 90 super.setImageDrawable(drawable); 91 if (mImageHelper != null) { 92 mImageHelper.applySupportImageTint(); 93 } 94 } 95 96 @Override setImageBitmap(Bitmap bm)97 public void setImageBitmap(Bitmap bm) { 98 super.setImageBitmap(bm); 99 if (mImageHelper != null) { 100 mImageHelper.applySupportImageTint(); 101 } 102 } 103 104 @Override setImageURI(@ullable Uri uri)105 public void setImageURI(@Nullable Uri uri) { 106 super.setImageURI(uri); 107 if (mImageHelper != null) { 108 mImageHelper.applySupportImageTint(); 109 } 110 } 111 112 @Override setBackgroundResource(@rawableRes int resId)113 public void setBackgroundResource(@DrawableRes int resId) { 114 super.setBackgroundResource(resId); 115 if (mBackgroundTintHelper != null) { 116 mBackgroundTintHelper.onSetBackgroundResource(resId); 117 } 118 } 119 120 @Override setBackgroundDrawable(Drawable background)121 public void setBackgroundDrawable(Drawable background) { 122 super.setBackgroundDrawable(background); 123 if (mBackgroundTintHelper != null) { 124 mBackgroundTintHelper.onSetBackgroundDrawable(background); 125 } 126 } 127 128 /** 129 * This should be accessed via 130 * {@link androidx.core.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} 131 * 132 * @hide 133 */ 134 @RestrictTo(LIBRARY_GROUP) 135 @Override setSupportBackgroundTintList(@ullable ColorStateList tint)136 public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { 137 if (mBackgroundTintHelper != null) { 138 mBackgroundTintHelper.setSupportBackgroundTintList(tint); 139 } 140 } 141 142 /** 143 * This should be accessed via 144 * {@link androidx.core.view.ViewCompat#getBackgroundTintList(android.view.View)} 145 * 146 * @hide 147 */ 148 @RestrictTo(LIBRARY_GROUP) 149 @Override 150 @Nullable getSupportBackgroundTintList()151 public ColorStateList getSupportBackgroundTintList() { 152 return mBackgroundTintHelper != null 153 ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; 154 } 155 156 /** 157 * This should be accessed via 158 * {@link androidx.core.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} 159 * 160 * @hide 161 */ 162 @RestrictTo(LIBRARY_GROUP) 163 @Override setSupportBackgroundTintMode(@ullable PorterDuff.Mode tintMode)164 public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 165 if (mBackgroundTintHelper != null) { 166 mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); 167 } 168 } 169 170 /** 171 * This should be accessed via 172 * {@link androidx.core.view.ViewCompat#getBackgroundTintMode(android.view.View)} 173 * 174 * @hide 175 */ 176 @RestrictTo(LIBRARY_GROUP) 177 @Override 178 @Nullable getSupportBackgroundTintMode()179 public PorterDuff.Mode getSupportBackgroundTintMode() { 180 return mBackgroundTintHelper != null 181 ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; 182 } 183 /** 184 * This should be accessed via 185 * {@link androidx.core.widget.ImageViewCompat#setImageTintList(ImageView, ColorStateList)} 186 * 187 * @hide 188 */ 189 @RestrictTo(LIBRARY_GROUP) 190 @Override setSupportImageTintList(@ullable ColorStateList tint)191 public void setSupportImageTintList(@Nullable ColorStateList tint) { 192 if (mImageHelper != null) { 193 mImageHelper.setSupportImageTintList(tint); 194 } 195 } 196 197 /** 198 * This should be accessed via 199 * {@link androidx.core.widget.ImageViewCompat#getImageTintList(ImageView)} 200 * 201 * @hide 202 */ 203 @RestrictTo(LIBRARY_GROUP) 204 @Override 205 @Nullable getSupportImageTintList()206 public ColorStateList getSupportImageTintList() { 207 return mImageHelper != null 208 ? mImageHelper.getSupportImageTintList() : null; 209 } 210 211 /** 212 * This should be accessed via 213 * {@link androidx.core.widget.ImageViewCompat#setImageTintMode(ImageView, PorterDuff.Mode)} 214 * 215 * @hide 216 */ 217 @RestrictTo(LIBRARY_GROUP) 218 @Override setSupportImageTintMode(@ullable PorterDuff.Mode tintMode)219 public void setSupportImageTintMode(@Nullable PorterDuff.Mode tintMode) { 220 if (mImageHelper != null) { 221 mImageHelper.setSupportImageTintMode(tintMode); 222 } 223 } 224 225 /** 226 * This should be accessed via 227 * {@link androidx.core.widget.ImageViewCompat#getImageTintMode(ImageView)} 228 * 229 * @hide 230 */ 231 @RestrictTo(LIBRARY_GROUP) 232 @Override 233 @Nullable getSupportImageTintMode()234 public PorterDuff.Mode getSupportImageTintMode() { 235 return mImageHelper != null 236 ? mImageHelper.getSupportImageTintMode() : null; 237 } 238 239 @Override drawableStateChanged()240 protected void drawableStateChanged() { 241 super.drawableStateChanged(); 242 if (mBackgroundTintHelper != null) { 243 mBackgroundTintHelper.applySupportBackgroundTint(); 244 } 245 if (mImageHelper != null) { 246 mImageHelper.applySupportImageTint(); 247 } 248 } 249 250 @Override hasOverlappingRendering()251 public boolean hasOverlappingRendering() { 252 return mImageHelper.hasOverlappingRendering() && super.hasOverlappingRendering(); 253 } 254 } 255