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 static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 20 21 import android.content.Context; 22 import android.content.res.ColorStateList; 23 import android.graphics.PorterDuff; 24 import android.graphics.drawable.Drawable; 25 import android.support.annotation.DrawableRes; 26 import android.support.annotation.NonNull; 27 import android.support.annotation.Nullable; 28 import android.support.annotation.RestrictTo; 29 import android.support.v4.os.BuildCompat; 30 import android.support.v4.view.TintableBackgroundView; 31 import android.support.v4.widget.AutoSizeableTextView; 32 import android.support.v4.widget.TextViewCompat; 33 import android.support.v7.appcompat.R; 34 import android.util.AttributeSet; 35 import android.widget.TextView; 36 37 /** 38 * A {@link TextView} which supports compatible features on older version of the platform, 39 * including: 40 * <ul> 41 * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to 42 * {@link android.os.Build.VERSION_CODES#GINGERBREAD Gingerbread}.</li> 43 * <li>Allows dynamic tint of its background via the background tint methods in 44 * {@link android.support.v4.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>Supports auto-sizing via {@link android.support.v4.widget.TextViewCompat} by allowing 48 * to instruct a {@link TextView} to let the size of the text expand or contract automatically 49 * to fill its layout based on the TextView's characteristics and boundaries. The 50 * style attributes associated with auto-sizing are {@link R.attr#autoSizeTextType}, 51 * {@link R.attr#autoSizeMinTextSize}, {@link R.attr#autoSizeMaxTextSize}, 52 * {@link R.attr#autoSizeStepGranularity} and {@link R.attr#autoSizePresetSizes}, all of 53 * which work back to 54 * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH Ice Cream Sandwich}.</li> 55 * </ul> 56 * 57 * <p>This will automatically be used when you use {@link TextView} in your layouts. 58 * You should only need to manually use this class when writing custom views.</p> 59 */ 60 public class AppCompatTextView extends TextView implements TintableBackgroundView, 61 AutoSizeableTextView { 62 63 private final AppCompatBackgroundHelper mBackgroundTintHelper; 64 private final AppCompatTextHelper mTextHelper; 65 AppCompatTextView(Context context)66 public AppCompatTextView(Context context) { 67 this(context, null); 68 } 69 AppCompatTextView(Context context, AttributeSet attrs)70 public AppCompatTextView(Context context, AttributeSet attrs) { 71 this(context, attrs, android.R.attr.textViewStyle); 72 } 73 AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr)74 public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) { 75 super(TintContextWrapper.wrap(context), attrs, defStyleAttr); 76 77 mBackgroundTintHelper = new AppCompatBackgroundHelper(this); 78 mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr); 79 80 mTextHelper = AppCompatTextHelper.create(this); 81 mTextHelper.loadFromAttributes(attrs, defStyleAttr); 82 mTextHelper.applyCompoundDrawablesTints(); 83 } 84 85 @Override setBackgroundResource(@rawableRes int resId)86 public void setBackgroundResource(@DrawableRes int resId) { 87 super.setBackgroundResource(resId); 88 if (mBackgroundTintHelper != null) { 89 mBackgroundTintHelper.onSetBackgroundResource(resId); 90 } 91 } 92 93 @Override setBackgroundDrawable(Drawable background)94 public void setBackgroundDrawable(Drawable background) { 95 super.setBackgroundDrawable(background); 96 if (mBackgroundTintHelper != null) { 97 mBackgroundTintHelper.onSetBackgroundDrawable(background); 98 } 99 } 100 101 /** 102 * This should be accessed via 103 * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)} 104 * 105 * @hide 106 */ 107 @RestrictTo(LIBRARY_GROUP) 108 @Override setSupportBackgroundTintList(@ullable ColorStateList tint)109 public void setSupportBackgroundTintList(@Nullable ColorStateList tint) { 110 if (mBackgroundTintHelper != null) { 111 mBackgroundTintHelper.setSupportBackgroundTintList(tint); 112 } 113 } 114 115 /** 116 * This should be accessed via 117 * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)} 118 * 119 * @hide 120 */ 121 @RestrictTo(LIBRARY_GROUP) 122 @Override 123 @Nullable getSupportBackgroundTintList()124 public ColorStateList getSupportBackgroundTintList() { 125 return mBackgroundTintHelper != null 126 ? mBackgroundTintHelper.getSupportBackgroundTintList() : null; 127 } 128 129 /** 130 * This should be accessed via 131 * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)} 132 * 133 * @hide 134 */ 135 @RestrictTo(LIBRARY_GROUP) 136 @Override setSupportBackgroundTintMode(@ullable PorterDuff.Mode tintMode)137 public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 138 if (mBackgroundTintHelper != null) { 139 mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode); 140 } 141 } 142 143 /** 144 * This should be accessed via 145 * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)} 146 * 147 * @hide 148 */ 149 @RestrictTo(LIBRARY_GROUP) 150 @Override 151 @Nullable getSupportBackgroundTintMode()152 public PorterDuff.Mode getSupportBackgroundTintMode() { 153 return mBackgroundTintHelper != null 154 ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null; 155 } 156 157 @Override setTextAppearance(Context context, int resId)158 public void setTextAppearance(Context context, int resId) { 159 super.setTextAppearance(context, resId); 160 if (mTextHelper != null) { 161 mTextHelper.onSetTextAppearance(context, resId); 162 } 163 } 164 165 @Override drawableStateChanged()166 protected void drawableStateChanged() { 167 super.drawableStateChanged(); 168 if (mBackgroundTintHelper != null) { 169 mBackgroundTintHelper.applySupportBackgroundTint(); 170 } 171 if (mTextHelper != null) { 172 mTextHelper.applyCompoundDrawablesTints(); 173 } 174 } 175 176 @Override onLayout(boolean changed, int left, int top, int right, int bottom)177 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 178 super.onLayout(changed, left, top, right, bottom); 179 if (mTextHelper != null) { 180 mTextHelper.onLayout(changed, left, top, right, bottom); 181 } 182 } 183 184 @Override setTextSize(int unit, float size)185 public void setTextSize(int unit, float size) { 186 if (BuildCompat.isAtLeastO()) { 187 super.setTextSize(unit, size); 188 } else { 189 if (mTextHelper != null) { 190 mTextHelper.setTextSize(unit, size); 191 } 192 } 193 } 194 195 /** 196 * This should be accessed via 197 * {@link android.support.v4.widget.TextViewCompat#setAutoSizeTextTypeWithDefaults( 198 * TextView, int)} 199 * 200 * @hide 201 */ 202 @RestrictTo(LIBRARY_GROUP) 203 @Override setAutoSizeTextTypeWithDefaults( @extViewCompat.AutoSizeTextType int autoSizeTextType)204 public void setAutoSizeTextTypeWithDefaults( 205 @TextViewCompat.AutoSizeTextType int autoSizeTextType) { 206 if (BuildCompat.isAtLeastO()) { 207 super.setAutoSizeTextTypeWithDefaults(autoSizeTextType); 208 } else { 209 if (mTextHelper != null) { 210 mTextHelper.setAutoSizeTextTypeWithDefaults(autoSizeTextType); 211 } 212 } 213 } 214 215 /** 216 * This should be accessed via 217 * {@link android.support.v4.widget.TextViewCompat#setAutoSizeTextTypeUniformWithConfiguration( 218 * TextView, int, int, int, int)} 219 * 220 * @hide 221 */ 222 @RestrictTo(LIBRARY_GROUP) 223 @Override setAutoSizeTextTypeUniformWithConfiguration( int autoSizeMinTextSize, int autoSizeMaxTextSize, int autoSizeStepGranularity, int unit)224 public void setAutoSizeTextTypeUniformWithConfiguration( 225 int autoSizeMinTextSize, 226 int autoSizeMaxTextSize, 227 int autoSizeStepGranularity, 228 int unit) throws IllegalArgumentException { 229 if (BuildCompat.isAtLeastO()) { 230 super.setAutoSizeTextTypeUniformWithConfiguration( 231 autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit); 232 } else { 233 if (mTextHelper != null) { 234 mTextHelper.setAutoSizeTextTypeUniformWithConfiguration( 235 autoSizeMinTextSize, autoSizeMaxTextSize, autoSizeStepGranularity, unit); 236 } 237 } 238 } 239 240 /** 241 * This should be accessed via 242 * {@link android.support.v4.widget.TextViewCompat#setAutoSizeTextTypeUniformWithPresetSizes( 243 * TextView, int[], int)} 244 * 245 * @hide 246 */ 247 @RestrictTo(LIBRARY_GROUP) 248 @Override setAutoSizeTextTypeUniformWithPresetSizes(@onNull int[] presetSizes, int unit)249 public void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[] presetSizes, int unit) 250 throws IllegalArgumentException { 251 if (BuildCompat.isAtLeastO()) { 252 super.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit); 253 } else { 254 if (mTextHelper != null) { 255 mTextHelper.setAutoSizeTextTypeUniformWithPresetSizes(presetSizes, unit); 256 } 257 } 258 } 259 260 /** 261 * This should be accessed via 262 * {@link android.support.v4.widget.TextViewCompat#getAutoSizeTextType(TextView)} 263 * 264 * @hide 265 */ 266 @RestrictTo(LIBRARY_GROUP) 267 @Override 268 @TextViewCompat.AutoSizeTextType getAutoSizeTextType()269 public int getAutoSizeTextType() { 270 if (BuildCompat.isAtLeastO()) { 271 return super.getAutoSizeTextType() == TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM 272 ? TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM 273 : TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE; 274 } else { 275 if (mTextHelper != null) { 276 return mTextHelper.getAutoSizeTextType(); 277 } 278 } 279 return TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE; 280 } 281 282 /** 283 * This should be accessed via 284 * {@link android.support.v4.widget.TextViewCompat#getAutoSizeStepGranularity(TextView)} 285 * 286 * @hide 287 */ 288 @RestrictTo(LIBRARY_GROUP) 289 @Override getAutoSizeStepGranularity()290 public int getAutoSizeStepGranularity() { 291 if (BuildCompat.isAtLeastO()) { 292 return super.getAutoSizeStepGranularity(); 293 } else { 294 if (mTextHelper != null) { 295 return mTextHelper.getAutoSizeStepGranularity(); 296 } 297 } 298 return -1; 299 } 300 301 /** 302 * This should be accessed via 303 * {@link android.support.v4.widget.TextViewCompat#getAutoSizeMinTextSize(TextView)} 304 * 305 * @hide 306 */ 307 @RestrictTo(LIBRARY_GROUP) 308 @Override getAutoSizeMinTextSize()309 public int getAutoSizeMinTextSize() { 310 if (BuildCompat.isAtLeastO()) { 311 return super.getAutoSizeMinTextSize(); 312 } else { 313 if (mTextHelper != null) { 314 return mTextHelper.getAutoSizeMinTextSize(); 315 } 316 } 317 return -1; 318 } 319 320 /** 321 * This should be accessed via 322 * {@link android.support.v4.widget.TextViewCompat#getAutoSizeMaxTextSize(TextView)} 323 * 324 * @hide 325 */ 326 @RestrictTo(LIBRARY_GROUP) 327 @Override getAutoSizeMaxTextSize()328 public int getAutoSizeMaxTextSize() { 329 if (BuildCompat.isAtLeastO()) { 330 return super.getAutoSizeMaxTextSize(); 331 } else { 332 if (mTextHelper != null) { 333 return mTextHelper.getAutoSizeMaxTextSize(); 334 } 335 } 336 return -1; 337 } 338 339 /** 340 * This should be accessed via 341 * {@link android.support.v4.widget.TextViewCompat#getAutoSizeTextAvailableSizes(TextView)} 342 * 343 * @hide 344 */ 345 @RestrictTo(LIBRARY_GROUP) 346 @Override getAutoSizeTextAvailableSizes()347 public int[] getAutoSizeTextAvailableSizes() { 348 if (BuildCompat.isAtLeastO()) { 349 return super.getAutoSizeTextAvailableSizes(); 350 } else { 351 if (mTextHelper != null) { 352 return mTextHelper.getAutoSizeTextAvailableSizes(); 353 } 354 } 355 return new int[0]; 356 } 357 } 358