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