blob: 572302a47330234c4e2d6139ec0012375032a6d0 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package android.widget;
18
Bjorn Bringert0f8555b2009-11-27 12:42:28 +000019import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.Context;
21import android.content.res.Resources;
22import android.content.res.TypedArray;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25import android.graphics.ColorFilter;
26import android.graphics.Matrix;
Alan Viverettee10dd532013-12-12 19:19:51 -080027import android.graphics.PixelFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.graphics.PorterDuff;
29import android.graphics.PorterDuffColorFilter;
Alan Viverettee10dd532013-12-12 19:19:51 -080030import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.RectF;
Adam Powell31049d72013-10-07 12:58:42 -070032import android.graphics.Xfermode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.drawable.BitmapDrawable;
34import android.graphics.drawable.Drawable;
35import android.net.Uri;
Adam Powell7da4b732012-12-07 15:28:33 -080036import android.os.Build;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070037import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.util.AttributeSet;
39import android.util.Log;
Jeff Sharkey2b95c242010-02-08 17:40:30 -080040import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.view.View;
Joe Onoratofd52b182010-11-10 18:00:52 -080042import android.view.ViewDebug;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070043import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080044import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.widget.RemoteViews.RemoteView;
46
Romain Guy36143942012-12-03 10:10:22 -080047import java.io.IOException;
48import java.io.InputStream;
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050/**
51 * Displays an arbitrary image, such as an icon. The ImageView class
52 * can load images from various sources (such as resources or content
53 * providers), takes care of computing its measurement from the image so that
54 * it can be used in any layout manager, and provides various display options
55 * such as scaling and tinting.
56 *
57 * @attr ref android.R.styleable#ImageView_adjustViewBounds
58 * @attr ref android.R.styleable#ImageView_src
59 * @attr ref android.R.styleable#ImageView_maxWidth
60 * @attr ref android.R.styleable#ImageView_maxHeight
61 * @attr ref android.R.styleable#ImageView_tint
62 * @attr ref android.R.styleable#ImageView_scaleType
63 * @attr ref android.R.styleable#ImageView_cropToPadding
64 */
65@RemoteView
66public class ImageView extends View {
67 // settable by the client
68 private Uri mUri;
69 private int mResource = 0;
70 private Matrix mMatrix;
71 private ScaleType mScaleType;
72 private boolean mHaveFrame = false;
73 private boolean mAdjustViewBounds = false;
74 private int mMaxWidth = Integer.MAX_VALUE;
75 private int mMaxHeight = Integer.MAX_VALUE;
76
77 // these are applied to the drawable
78 private ColorFilter mColorFilter;
Adam Powell31049d72013-10-07 12:58:42 -070079 private Xfermode mXfermode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 private int mAlpha = 255;
81 private int mViewAlphaScale = 256;
Jeff Sharkey2b95c242010-02-08 17:40:30 -080082 private boolean mColorMod = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84 private Drawable mDrawable = null;
85 private int[] mState = null;
86 private boolean mMergeState = false;
87 private int mLevel = 0;
88 private int mDrawableWidth;
89 private int mDrawableHeight;
90 private Matrix mDrawMatrix = null;
91
92 // Avoid allocations...
93 private RectF mTempSrc = new RectF();
94 private RectF mTempDst = new RectF();
95
96 private boolean mCropToPadding;
97
Joe Onoratofd52b182010-11-10 18:00:52 -080098 private int mBaseline = -1;
99 private boolean mBaselineAlignBottom = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Adam Powell7da4b732012-12-07 15:28:33 -0800101 // AdjustViewBounds behavior will be in compatibility mode for older apps.
102 private boolean mAdjustViewBoundsCompat = false;
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final ScaleType[] sScaleTypeArray = {
105 ScaleType.MATRIX,
106 ScaleType.FIT_XY,
107 ScaleType.FIT_START,
108 ScaleType.FIT_CENTER,
109 ScaleType.FIT_END,
110 ScaleType.CENTER,
111 ScaleType.CENTER_CROP,
112 ScaleType.CENTER_INSIDE
113 };
114
115 public ImageView(Context context) {
116 super(context);
117 initImageView();
118 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 public ImageView(Context context, AttributeSet attrs) {
121 this(context, attrs, 0);
122 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700123
Alan Viverette617feb92013-09-09 18:09:13 -0700124 public ImageView(Context context, AttributeSet attrs, int defStyleAttr) {
125 this(context, attrs, defStyleAttr, 0);
126 }
127
128 public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
129 super(context, attrs, defStyleAttr, defStyleRes);
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 initImageView();
132
Alan Viverette617feb92013-09-09 18:09:13 -0700133 final TypedArray a = context.obtainStyledAttributes(
134 attrs, com.android.internal.R.styleable.ImageView, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135
136 Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);
137 if (d != null) {
138 setImageDrawable(d);
139 }
140
Joe Onoratofd52b182010-11-10 18:00:52 -0800141 mBaselineAlignBottom = a.getBoolean(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 com.android.internal.R.styleable.ImageView_baselineAlignBottom, false);
Joe Onoratofd52b182010-11-10 18:00:52 -0800143
144 mBaseline = a.getDimensionPixelSize(
145 com.android.internal.R.styleable.ImageView_baseline, -1);
146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 setAdjustViewBounds(
148 a.getBoolean(com.android.internal.R.styleable.ImageView_adjustViewBounds,
149 false));
150
151 setMaxWidth(a.getDimensionPixelSize(
152 com.android.internal.R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
153
154 setMaxHeight(a.getDimensionPixelSize(
155 com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
156
157 int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
158 if (index >= 0) {
159 setScaleType(sScaleTypeArray[index]);
160 }
161
162 int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
163 if (tint != 0) {
Jeff Sharkey2b95c242010-02-08 17:40:30 -0800164 setColorFilter(tint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 }
166
Chet Haaseba1fe8e2011-10-15 07:35:51 -0700167 int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
168 if (alpha != 255) {
169 setAlpha(alpha);
170 }
171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 mCropToPadding = a.getBoolean(
173 com.android.internal.R.styleable.ImageView_cropToPadding, false);
174
175 a.recycle();
176
177 //need inflate syntax/reader for matrix
178 }
179
180 private void initImageView() {
181 mMatrix = new Matrix();
182 mScaleType = ScaleType.FIT_CENTER;
Adam Powell7da4b732012-12-07 15:28:33 -0800183 mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <=
184 Build.VERSION_CODES.JELLY_BEAN_MR1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 }
186
187 @Override
188 protected boolean verifyDrawable(Drawable dr) {
189 return mDrawable == dr || super.verifyDrawable(dr);
190 }
191
192 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700193 public void jumpDrawablesToCurrentState() {
194 super.jumpDrawablesToCurrentState();
195 if (mDrawable != null) mDrawable.jumpToCurrentState();
196 }
197
198 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 public void invalidateDrawable(Drawable dr) {
200 if (dr == mDrawable) {
201 /* we invalidate the whole view in this case because it's very
202 * hard to know where the drawable actually is. This is made
203 * complicated because of the offsets and transformations that
204 * can be applied. In theory we could get the drawable's bounds
205 * and run them through the transformation and offsets, but this
206 * is probably not worth the effort.
207 */
208 invalidate();
209 } else {
210 super.invalidateDrawable(dr);
211 }
212 }
Joe Onoratofd52b182010-11-10 18:00:52 -0800213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 @Override
Chet Haasedb8c9a62012-03-21 18:54:18 -0700215 public boolean hasOverlappingRendering() {
Michael Jurka0931a852013-03-21 16:07:45 +0100216 return (getBackground() != null && getBackground().getCurrent() != null);
Chet Haasedb8c9a62012-03-21 18:54:18 -0700217 }
218
219 @Override
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700220 public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700221 super.onPopulateAccessibilityEvent(event);
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700222 CharSequence contentDescription = getContentDescription();
223 if (!TextUtils.isEmpty(contentDescription)) {
224 event.getText().add(contentDescription);
225 }
226 }
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 /**
Philip Milneaac722a2012-03-26 13:30:26 -0700229 * True when ImageView is adjusting its bounds
230 * to preserve the aspect ratio of its drawable
231 *
232 * @return whether to adjust the bounds of this view
233 * to presrve the original aspect ratio of the drawable
234 *
235 * @see #setAdjustViewBounds(boolean)
236 *
237 * @attr ref android.R.styleable#ImageView_adjustViewBounds
238 */
239 public boolean getAdjustViewBounds() {
240 return mAdjustViewBounds;
241 }
242
243 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 * Set this to true if you want the ImageView to adjust its bounds
245 * to preserve the aspect ratio of its drawable.
Adam Powell2c8cc972012-12-07 18:04:51 -0800246 *
247 * <p><strong>Note:</strong> If the application targets API level 17 or lower,
248 * adjustViewBounds will allow the drawable to shrink the view bounds, but not grow
249 * to fill available measured space in all cases. This is for compatibility with
250 * legacy {@link android.view.View.MeasureSpec MeasureSpec} and
251 * {@link android.widget.RelativeLayout RelativeLayout} behavior.</p>
252 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 * @param adjustViewBounds Whether to adjust the bounds of this view
Adam Powell2c8cc972012-12-07 18:04:51 -0800254 * to preserve the original aspect ratio of the drawable.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 *
Philip Milneaac722a2012-03-26 13:30:26 -0700256 * @see #getAdjustViewBounds()
257 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 * @attr ref android.R.styleable#ImageView_adjustViewBounds
259 */
260 @android.view.RemotableViewMethod
261 public void setAdjustViewBounds(boolean adjustViewBounds) {
262 mAdjustViewBounds = adjustViewBounds;
263 if (adjustViewBounds) {
264 setScaleType(ScaleType.FIT_CENTER);
265 }
266 }
Philip Milneaac722a2012-03-26 13:30:26 -0700267
268 /**
269 * The maximum width of this view.
270 *
271 * @return The maximum width of this view
272 *
273 * @see #setMaxWidth(int)
274 *
275 * @attr ref android.R.styleable#ImageView_maxWidth
276 */
277 public int getMaxWidth() {
278 return mMaxWidth;
279 }
280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 /**
282 * An optional argument to supply a maximum width for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700283 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a maximum
284 * of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
285 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
286 * layout params to WRAP_CONTENT.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 *
288 * <p>
289 * Note that this view could be still smaller than 100 x 100 using this approach if the original
290 * image is small. To set an image to a fixed size, specify that size in the layout params and
Romain Guy9fc27812011-04-27 14:21:41 -0700291 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
292 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 * </p>
294 *
295 * @param maxWidth maximum width for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700296 *
297 * @see #getMaxWidth()
298 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 * @attr ref android.R.styleable#ImageView_maxWidth
300 */
301 @android.view.RemotableViewMethod
302 public void setMaxWidth(int maxWidth) {
303 mMaxWidth = maxWidth;
304 }
Philip Milneaac722a2012-03-26 13:30:26 -0700305
306 /**
307 * The maximum height of this view.
308 *
309 * @return The maximum height of this view
310 *
311 * @see #setMaxHeight(int)
312 *
313 * @attr ref android.R.styleable#ImageView_maxHeight
314 */
315 public int getMaxHeight() {
316 return mMaxHeight;
317 }
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 /**
320 * An optional argument to supply a maximum height for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700321 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
322 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
323 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
324 * layout params to WRAP_CONTENT.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 *
326 * <p>
327 * Note that this view could be still smaller than 100 x 100 using this approach if the original
328 * image is small. To set an image to a fixed size, specify that size in the layout params and
Romain Guy9fc27812011-04-27 14:21:41 -0700329 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
330 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 * </p>
332 *
333 * @param maxHeight maximum height for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700334 *
335 * @see #getMaxHeight()
336 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 * @attr ref android.R.styleable#ImageView_maxHeight
338 */
339 @android.view.RemotableViewMethod
340 public void setMaxHeight(int maxHeight) {
341 mMaxHeight = maxHeight;
342 }
343
344 /** Return the view's drawable, or null if no drawable has been
345 assigned.
346 */
347 public Drawable getDrawable() {
348 return mDrawable;
349 }
350
351 /**
352 * Sets a drawable as the content of this ImageView.
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700353 *
354 * <p class="note">This does Bitmap reading and decoding on the UI
355 * thread, which can cause a latency hiccup. If that's a concern,
Romain Guy9fc27812011-04-27 14:21:41 -0700356 * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
357 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700358 * {@link android.graphics.BitmapFactory} instead.</p>
359 *
Chet Haase430742f2013-04-12 11:18:36 -0700360 * @param resId the resource identifier of the drawable
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700361 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 * @attr ref android.R.styleable#ImageView_src
363 */
364 @android.view.RemotableViewMethod
365 public void setImageResource(int resId) {
366 if (mUri != null || mResource != resId) {
Alan Viverette4803bc12014-02-03 14:32:07 -0800367 final int oldWidth = mDrawableWidth;
368 final int oldHeight = mDrawableHeight;
369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 updateDrawable(null);
371 mResource = resId;
372 mUri = null;
Adam Powellf96ce022012-08-09 15:08:33 -0700373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700375
376 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
377 requestLayout();
378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 invalidate();
380 }
381 }
382
383 /**
384 * Sets the content of this ImageView to the specified Uri.
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700385 *
386 * <p class="note">This does Bitmap reading and decoding on the UI
387 * thread, which can cause a latency hiccup. If that's a concern,
Romain Guy9fc27812011-04-27 14:21:41 -0700388 * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
389 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700390 * {@link android.graphics.BitmapFactory} instead.</p>
391 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 * @param uri The Uri of an image
393 */
394 @android.view.RemotableViewMethod
395 public void setImageURI(Uri uri) {
396 if (mResource != 0 ||
397 (mUri != uri &&
398 (uri == null || mUri == null || !uri.equals(mUri)))) {
399 updateDrawable(null);
400 mResource = 0;
401 mUri = uri;
Adam Powellf96ce022012-08-09 15:08:33 -0700402
403 final int oldWidth = mDrawableWidth;
404 final int oldHeight = mDrawableHeight;
405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700407
408 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
409 requestLayout();
410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 invalidate();
412 }
413 }
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 /**
416 * Sets a drawable as the content of this ImageView.
417 *
418 * @param drawable The drawable to set
419 */
420 public void setImageDrawable(Drawable drawable) {
421 if (mDrawable != drawable) {
422 mResource = 0;
423 mUri = null;
Romain Guy9e648c42011-08-17 20:04:27 -0700424
Adam Powellf96ce022012-08-09 15:08:33 -0700425 final int oldWidth = mDrawableWidth;
426 final int oldHeight = mDrawableHeight;
Romain Guy9e648c42011-08-17 20:04:27 -0700427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 updateDrawable(drawable);
Adam Powell2a0e99d2011-08-04 10:55:03 -0700429
Romain Guy9e648c42011-08-17 20:04:27 -0700430 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
Adam Powell2a0e99d2011-08-04 10:55:03 -0700431 requestLayout();
432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 invalidate();
434 }
435 }
436
437 /**
438 * Sets a Bitmap as the content of this ImageView.
439 *
440 * @param bm The bitmap to set
441 */
442 @android.view.RemotableViewMethod
443 public void setImageBitmap(Bitmap bm) {
444 // if this is used frequently, may handle bitmaps explicitly
445 // to reduce the intermediate drawable object
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700446 setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 }
448
449 public void setImageState(int[] state, boolean merge) {
450 mState = state;
451 mMergeState = merge;
452 if (mDrawable != null) {
453 refreshDrawableState();
454 resizeFromDrawable();
455 }
456 }
457
458 @Override
459 public void setSelected(boolean selected) {
460 super.setSelected(selected);
461 resizeFromDrawable();
462 }
463
The Android Open Source Project4df24232009-03-05 14:34:35 -0800464 /**
465 * Sets the image level, when it is constructed from a
466 * {@link android.graphics.drawable.LevelListDrawable}.
467 *
468 * @param level The new level for the image.
469 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 @android.view.RemotableViewMethod
471 public void setImageLevel(int level) {
472 mLevel = level;
473 if (mDrawable != null) {
474 mDrawable.setLevel(level);
475 resizeFromDrawable();
476 }
477 }
478
479 /**
480 * Options for scaling the bounds of an image to the bounds of this view.
481 */
482 public enum ScaleType {
483 /**
484 * Scale using the image matrix when drawing. The image matrix can be set using
485 * {@link ImageView#setImageMatrix(Matrix)}. From XML, use this syntax:
486 * <code>android:scaleType="matrix"</code>.
487 */
488 MATRIX (0),
489 /**
490 * Scale the image using {@link Matrix.ScaleToFit#FILL}.
491 * From XML, use this syntax: <code>android:scaleType="fitXY"</code>.
492 */
493 FIT_XY (1),
494 /**
495 * Scale the image using {@link Matrix.ScaleToFit#START}.
496 * From XML, use this syntax: <code>android:scaleType="fitStart"</code>.
497 */
498 FIT_START (2),
499 /**
500 * Scale the image using {@link Matrix.ScaleToFit#CENTER}.
501 * From XML, use this syntax:
502 * <code>android:scaleType="fitCenter"</code>.
503 */
504 FIT_CENTER (3),
505 /**
506 * Scale the image using {@link Matrix.ScaleToFit#END}.
507 * From XML, use this syntax: <code>android:scaleType="fitEnd"</code>.
508 */
509 FIT_END (4),
510 /**
511 * Center the image in the view, but perform no scaling.
512 * From XML, use this syntax: <code>android:scaleType="center"</code>.
513 */
514 CENTER (5),
515 /**
516 * Scale the image uniformly (maintain the image's aspect ratio) so
517 * that both dimensions (width and height) of the image will be equal
518 * to or larger than the corresponding dimension of the view
519 * (minus padding). The image is then centered in the view.
520 * From XML, use this syntax: <code>android:scaleType="centerCrop"</code>.
521 */
522 CENTER_CROP (6),
523 /**
524 * Scale the image uniformly (maintain the image's aspect ratio) so
525 * that both dimensions (width and height) of the image will be equal
526 * to or less than the corresponding dimension of the view
527 * (minus padding). The image is then centered in the view.
528 * From XML, use this syntax: <code>android:scaleType="centerInside"</code>.
529 */
530 CENTER_INSIDE (7);
531
532 ScaleType(int ni) {
533 nativeInt = ni;
534 }
535 final int nativeInt;
536 }
537
538 /**
539 * Controls how the image should be resized or moved to match the size
540 * of this ImageView.
541 *
542 * @param scaleType The desired scaling mode.
543 *
544 * @attr ref android.R.styleable#ImageView_scaleType
545 */
546 public void setScaleType(ScaleType scaleType) {
547 if (scaleType == null) {
548 throw new NullPointerException();
549 }
550
551 if (mScaleType != scaleType) {
552 mScaleType = scaleType;
553
554 setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
555
556 requestLayout();
557 invalidate();
558 }
559 }
560
561 /**
562 * Return the current scale type in use by this ImageView.
563 *
564 * @see ImageView.ScaleType
565 *
566 * @attr ref android.R.styleable#ImageView_scaleType
567 */
568 public ScaleType getScaleType() {
569 return mScaleType;
570 }
571
572 /** Return the view's optional matrix. This is applied to the
John Spurlock0196e562014-02-03 09:00:35 -0500573 view's drawable when it is drawn. If there is no matrix,
Romain Guy53704052013-01-30 16:25:50 -0800574 this method will return an identity matrix.
575 Do not change this matrix in place but make a copy.
576 If you want a different matrix applied to the drawable,
577 be sure to call setImageMatrix().
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 */
579 public Matrix getImageMatrix() {
Dake Gu1ee60172013-01-03 15:11:43 -0800580 if (mDrawMatrix == null) {
Romain Guy53704052013-01-30 16:25:50 -0800581 return new Matrix(Matrix.IDENTITY_MATRIX);
Dake Gu1ee60172013-01-03 15:11:43 -0800582 }
583 return mDrawMatrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 }
585
586 public void setImageMatrix(Matrix matrix) {
587 // collaps null and identity to just null
588 if (matrix != null && matrix.isIdentity()) {
589 matrix = null;
590 }
591
592 // don't invalidate unless we're actually changing our matrix
593 if (matrix == null && !mMatrix.isIdentity() ||
594 matrix != null && !mMatrix.equals(matrix)) {
595 mMatrix.set(matrix);
Chih-Chung Changf8887262009-07-30 15:36:13 +0800596 configureBounds();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 invalidate();
598 }
599 }
Philip Milneaac722a2012-03-26 13:30:26 -0700600
601 /**
602 * Return whether this ImageView crops to padding.
603 *
604 * @return whether this ImageView crops to padding
605 *
606 * @see #setCropToPadding(boolean)
607 *
608 * @attr ref android.R.styleable#ImageView_cropToPadding
609 */
610 public boolean getCropToPadding() {
611 return mCropToPadding;
612 }
613
614 /**
615 * Sets whether this ImageView will crop to padding.
616 *
617 * @param cropToPadding whether this ImageView will crop to padding
618 *
619 * @see #getCropToPadding()
620 *
621 * @attr ref android.R.styleable#ImageView_cropToPadding
622 */
623 public void setCropToPadding(boolean cropToPadding) {
624 if (mCropToPadding != cropToPadding) {
625 mCropToPadding = cropToPadding;
626 requestLayout();
627 invalidate();
628 }
629 }
630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 private void resolveUri() {
632 if (mDrawable != null) {
633 return;
634 }
635
636 Resources rsrc = getResources();
637 if (rsrc == null) {
638 return;
639 }
640
641 Drawable d = null;
642
643 if (mResource != 0) {
644 try {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800645 d = mContext.getDrawable(mResource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 } catch (Exception e) {
647 Log.w("ImageView", "Unable to find resource: " + mResource, e);
648 // Don't try again.
649 mUri = null;
650 }
651 } else if (mUri != null) {
Bjorn Bringert0f8555b2009-11-27 12:42:28 +0000652 String scheme = mUri.getScheme();
Bjorn Bringert9d8d9c22010-01-06 22:52:41 +0000653 if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
654 try {
655 // Load drawable through Resources, to get the source density information
656 ContentResolver.OpenResourceIdResult r =
657 mContext.getContentResolver().getResourceId(mUri);
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800658 d = r.r.getDrawable(r.id, mContext.getTheme());
Bjorn Bringert9d8d9c22010-01-06 22:52:41 +0000659 } catch (Exception e) {
660 Log.w("ImageView", "Unable to open content: " + mUri, e);
661 }
662 } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
Bjorn Bringert0f8555b2009-11-27 12:42:28 +0000663 || ContentResolver.SCHEME_FILE.equals(scheme)) {
Romain Guy36143942012-12-03 10:10:22 -0800664 InputStream stream = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 try {
Romain Guy36143942012-12-03 10:10:22 -0800666 stream = mContext.getContentResolver().openInputStream(mUri);
667 d = Drawable.createFromStream(stream, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 } catch (Exception e) {
669 Log.w("ImageView", "Unable to open content: " + mUri, e);
Romain Guy36143942012-12-03 10:10:22 -0800670 } finally {
671 if (stream != null) {
672 try {
673 stream.close();
674 } catch (IOException e) {
675 Log.w("ImageView", "Unable to close content: " + mUri, e);
676 }
677 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 }
Romain Guy36143942012-12-03 10:10:22 -0800679 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 d = Drawable.createFromPath(mUri.toString());
681 }
682
683 if (d == null) {
Romain Guy36143942012-12-03 10:10:22 -0800684 System.out.println("resolveUri failed on bad bitmap uri: " + mUri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 // Don't try again.
686 mUri = null;
687 }
688 } else {
689 return;
690 }
691
692 updateDrawable(d);
693 }
694
695 @Override
696 public int[] onCreateDrawableState(int extraSpace) {
697 if (mState == null) {
698 return super.onCreateDrawableState(extraSpace);
699 } else if (!mMergeState) {
700 return mState;
701 } else {
702 return mergeDrawableStates(
703 super.onCreateDrawableState(extraSpace + mState.length), mState);
704 }
705 }
706
707 private void updateDrawable(Drawable d) {
708 if (mDrawable != null) {
709 mDrawable.setCallback(null);
710 unscheduleDrawable(mDrawable);
711 }
712 mDrawable = d;
713 if (d != null) {
714 d.setCallback(this);
715 if (d.isStateful()) {
716 d.setState(getDrawableState());
717 }
718 d.setLevel(mLevel);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700719 d.setLayoutDirection(getLayoutDirection());
Jeff Browne2126ba2013-11-08 13:55:55 -0800720 d.setVisible(getVisibility() == VISIBLE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 mDrawableWidth = d.getIntrinsicWidth();
722 mDrawableHeight = d.getIntrinsicHeight();
723 applyColorMod();
724 configureBounds();
Romain Guy9e648c42011-08-17 20:04:27 -0700725 } else {
726 mDrawableWidth = mDrawableHeight = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 }
728 }
729
730 private void resizeFromDrawable() {
731 Drawable d = mDrawable;
732 if (d != null) {
733 int w = d.getIntrinsicWidth();
734 if (w < 0) w = mDrawableWidth;
735 int h = d.getIntrinsicHeight();
736 if (h < 0) h = mDrawableHeight;
737 if (w != mDrawableWidth || h != mDrawableHeight) {
738 mDrawableWidth = w;
739 mDrawableHeight = h;
740 requestLayout();
741 }
742 }
743 }
744
Fabrice Di Meglio3f5a90b2013-06-24 19:22:25 -0700745 @Override
746 public void onRtlPropertiesChanged(int layoutDirection) {
747 super.onRtlPropertiesChanged(layoutDirection);
748
749 if (mDrawable != null) {
750 mDrawable.setLayoutDirection(layoutDirection);
751 }
752 }
753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 private static final Matrix.ScaleToFit[] sS2FArray = {
755 Matrix.ScaleToFit.FILL,
756 Matrix.ScaleToFit.START,
757 Matrix.ScaleToFit.CENTER,
758 Matrix.ScaleToFit.END
759 };
760
761 private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
762 // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
763 return sS2FArray[st.nativeInt - 1];
764 }
765
766 @Override
767 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
768 resolveUri();
769 int w;
770 int h;
771
772 // Desired aspect ratio of the view's contents (not including padding)
773 float desiredAspect = 0.0f;
774
775 // We are allowed to change the view's width
776 boolean resizeWidth = false;
777
778 // We are allowed to change the view's height
779 boolean resizeHeight = false;
780
Adam Powell2a0e99d2011-08-04 10:55:03 -0700781 final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
782 final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 if (mDrawable == null) {
785 // If no drawable, its intrinsic size is 0.
786 mDrawableWidth = -1;
787 mDrawableHeight = -1;
788 w = h = 0;
789 } else {
790 w = mDrawableWidth;
791 h = mDrawableHeight;
792 if (w <= 0) w = 1;
793 if (h <= 0) h = 1;
Romain Guy9e648c42011-08-17 20:04:27 -0700794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 // We are supposed to adjust view bounds to match the aspect
796 // ratio of our drawable. See if that is possible.
797 if (mAdjustViewBounds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
799 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
800
Romain Guy9e648c42011-08-17 20:04:27 -0700801 desiredAspect = (float) w / (float) h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
803 }
804
805 int pleft = mPaddingLeft;
806 int pright = mPaddingRight;
807 int ptop = mPaddingTop;
808 int pbottom = mPaddingBottom;
809
810 int widthSize;
811 int heightSize;
812
813 if (resizeWidth || resizeHeight) {
814 /* If we get here, it means we want to resize to match the
815 drawables aspect ratio, and we have the freedom to change at
816 least one dimension.
817 */
818
819 // Get the max possible width given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -0700820 widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);
821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 // Get the max possible height given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -0700823 heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);
824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 if (desiredAspect != 0.0f) {
826 // See what our actual aspect ratio is
827 float actualAspect = (float)(widthSize - pleft - pright) /
828 (heightSize - ptop - pbottom);
829
830 if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
831
832 boolean done = false;
833
834 // Try adjusting width to be proportional to height
835 if (resizeWidth) {
Romain Guy9e648c42011-08-17 20:04:27 -0700836 int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
837 pleft + pright;
Adam Powelld5edc772012-09-26 15:21:39 -0700838
839 // Allow the width to outgrow its original estimate if height is fixed.
Adam Powell7da4b732012-12-07 15:28:33 -0800840 if (!resizeHeight && !mAdjustViewBoundsCompat) {
Adam Powelld5edc772012-09-26 15:21:39 -0700841 widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
842 }
843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 if (newWidth <= widthSize) {
845 widthSize = newWidth;
846 done = true;
847 }
848 }
849
850 // Try adjusting height to be proportional to width
851 if (!done && resizeHeight) {
Romain Guy9e648c42011-08-17 20:04:27 -0700852 int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
853 ptop + pbottom;
Adam Powelld5edc772012-09-26 15:21:39 -0700854
855 // Allow the height to outgrow its original estimate if width is fixed.
Adam Powell7da4b732012-12-07 15:28:33 -0800856 if (!resizeWidth && !mAdjustViewBoundsCompat) {
Adam Powelld5edc772012-09-26 15:21:39 -0700857 heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
858 heightMeasureSpec);
859 }
860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 if (newHeight <= heightSize) {
862 heightSize = newHeight;
Dianne Hackborn189ee182010-12-02 21:48:53 -0800863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 }
865 }
866 }
867 } else {
868 /* We are either don't want to preserve the drawables aspect ratio,
869 or we are not allowed to change view dimensions. Just measure in
870 the normal way.
871 */
872 w += pleft + pright;
873 h += ptop + pbottom;
874
875 w = Math.max(w, getSuggestedMinimumWidth());
876 h = Math.max(h, getSuggestedMinimumHeight());
877
Dianne Hackborn189ee182010-12-02 21:48:53 -0800878 widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
879 heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 }
881
882 setMeasuredDimension(widthSize, heightSize);
883 }
884
885 private int resolveAdjustedSize(int desiredSize, int maxSize,
886 int measureSpec) {
887 int result = desiredSize;
888 int specMode = MeasureSpec.getMode(measureSpec);
889 int specSize = MeasureSpec.getSize(measureSpec);
890 switch (specMode) {
891 case MeasureSpec.UNSPECIFIED:
892 /* Parent says we can be as big as we want. Just don't be larger
893 than max size imposed on ourselves.
894 */
895 result = Math.min(desiredSize, maxSize);
896 break;
897 case MeasureSpec.AT_MOST:
898 // Parent says we can be as big as we want, up to specSize.
899 // Don't be larger than specSize, and don't be larger than
900 // the max size imposed on ourselves.
901 result = Math.min(Math.min(desiredSize, specSize), maxSize);
902 break;
903 case MeasureSpec.EXACTLY:
904 // No choice. Do what we are told.
905 result = specSize;
906 break;
907 }
908 return result;
909 }
910
911 @Override
912 protected boolean setFrame(int l, int t, int r, int b) {
913 boolean changed = super.setFrame(l, t, r, b);
914 mHaveFrame = true;
915 configureBounds();
916 return changed;
917 }
918
919 private void configureBounds() {
920 if (mDrawable == null || !mHaveFrame) {
921 return;
922 }
923
924 int dwidth = mDrawableWidth;
925 int dheight = mDrawableHeight;
926
927 int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
928 int vheight = getHeight() - mPaddingTop - mPaddingBottom;
929
930 boolean fits = (dwidth < 0 || vwidth == dwidth) &&
931 (dheight < 0 || vheight == dheight);
932
933 if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
934 /* If the drawable has no intrinsic size, or we're told to
935 scaletofit, then we just fill our entire view.
936 */
937 mDrawable.setBounds(0, 0, vwidth, vheight);
938 mDrawMatrix = null;
939 } else {
940 // We need to do the scaling ourself, so have the drawable
941 // use its native size.
942 mDrawable.setBounds(0, 0, dwidth, dheight);
943
944 if (ScaleType.MATRIX == mScaleType) {
945 // Use the specified matrix as-is.
946 if (mMatrix.isIdentity()) {
947 mDrawMatrix = null;
948 } else {
949 mDrawMatrix = mMatrix;
950 }
951 } else if (fits) {
952 // The bitmap fits exactly, no transform needed.
953 mDrawMatrix = null;
954 } else if (ScaleType.CENTER == mScaleType) {
955 // Center bitmap in view, no scaling.
956 mDrawMatrix = mMatrix;
Romain Guyb4938202010-03-15 17:53:37 -0700957 mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),
958 (int) ((vheight - dheight) * 0.5f + 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 } else if (ScaleType.CENTER_CROP == mScaleType) {
960 mDrawMatrix = mMatrix;
961
962 float scale;
963 float dx = 0, dy = 0;
964
965 if (dwidth * vheight > vwidth * dheight) {
966 scale = (float) vheight / (float) dheight;
967 dx = (vwidth - dwidth * scale) * 0.5f;
968 } else {
969 scale = (float) vwidth / (float) dwidth;
970 dy = (vheight - dheight * scale) * 0.5f;
971 }
972
973 mDrawMatrix.setScale(scale, scale);
Romain Guyb4938202010-03-15 17:53:37 -0700974 mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 } else if (ScaleType.CENTER_INSIDE == mScaleType) {
976 mDrawMatrix = mMatrix;
977 float scale;
978 float dx;
979 float dy;
980
981 if (dwidth <= vwidth && dheight <= vheight) {
982 scale = 1.0f;
983 } else {
Romain Guy9e648c42011-08-17 20:04:27 -0700984 scale = Math.min((float) vwidth / (float) dwidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 (float) vheight / (float) dheight);
986 }
987
Romain Guyb4938202010-03-15 17:53:37 -0700988 dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
989 dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990
991 mDrawMatrix.setScale(scale, scale);
992 mDrawMatrix.postTranslate(dx, dy);
993 } else {
994 // Generate the required transform.
995 mTempSrc.set(0, 0, dwidth, dheight);
996 mTempDst.set(0, 0, vwidth, vheight);
997
998 mDrawMatrix = mMatrix;
Romain Guy9e648c42011-08-17 20:04:27 -0700999 mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
1001 }
1002 }
1003
1004 @Override
1005 protected void drawableStateChanged() {
1006 super.drawableStateChanged();
1007 Drawable d = mDrawable;
1008 if (d != null && d.isStateful()) {
1009 d.setState(getDrawableState());
1010 }
1011 }
1012
1013 @Override
1014 protected void onDraw(Canvas canvas) {
1015 super.onDraw(canvas);
1016
1017 if (mDrawable == null) {
1018 return; // couldn't resolve the URI
1019 }
1020
1021 if (mDrawableWidth == 0 || mDrawableHeight == 0) {
1022 return; // nothing to draw (empty bounds)
1023 }
1024
1025 if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
1026 mDrawable.draw(canvas);
1027 } else {
1028 int saveCount = canvas.getSaveCount();
1029 canvas.save();
1030
1031 if (mCropToPadding) {
1032 final int scrollX = mScrollX;
1033 final int scrollY = mScrollY;
1034 canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
1035 scrollX + mRight - mLeft - mPaddingRight,
1036 scrollY + mBottom - mTop - mPaddingBottom);
1037 }
1038
1039 canvas.translate(mPaddingLeft, mPaddingTop);
1040
1041 if (mDrawMatrix != null) {
1042 canvas.concat(mDrawMatrix);
1043 }
1044 mDrawable.draw(canvas);
1045 canvas.restoreToCount(saveCount);
1046 }
1047 }
1048
Joe Onoratofd52b182010-11-10 18:00:52 -08001049 /**
1050 * <p>Return the offset of the widget's text baseline from the widget's top
1051 * boundary. </p>
1052 *
1053 * @return the offset of the baseline within the widget's bounds or -1
1054 * if baseline alignment is not supported.
1055 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 @Override
Joe Onoratofd52b182010-11-10 18:00:52 -08001057 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 public int getBaseline() {
Joe Onoratofd52b182010-11-10 18:00:52 -08001059 if (mBaselineAlignBottom) {
1060 return getMeasuredHeight();
1061 } else {
1062 return mBaseline;
1063 }
1064 }
1065
1066 /**
1067 * <p>Set the offset of the widget's text baseline from the widget's top
Romain Guy9fc27812011-04-27 14:21:41 -07001068 * boundary. This value is overridden by the {@link #setBaselineAlignBottom(boolean)}
Joe Onoratofd52b182010-11-10 18:00:52 -08001069 * property.</p>
1070 *
1071 * @param baseline The baseline to use, or -1 if none is to be provided.
1072 *
Romain Guy9fc27812011-04-27 14:21:41 -07001073 * @see #setBaseline(int)
Joe Onoratofd52b182010-11-10 18:00:52 -08001074 * @attr ref android.R.styleable#ImageView_baseline
1075 */
1076 public void setBaseline(int baseline) {
1077 if (mBaseline != baseline) {
1078 mBaseline = baseline;
1079 requestLayout();
1080 }
1081 }
1082
1083 /**
1084 * Set whether to set the baseline of this view to the bottom of the view.
1085 * Setting this value overrides any calls to setBaseline.
1086 *
1087 * @param aligned If true, the image view will be baseline aligned with
1088 * based on its bottom edge.
1089 *
1090 * @attr ref android.R.styleable#ImageView_baselineAlignBottom
1091 */
1092 public void setBaselineAlignBottom(boolean aligned) {
1093 if (mBaselineAlignBottom != aligned) {
1094 mBaselineAlignBottom = aligned;
1095 requestLayout();
1096 }
1097 }
1098
1099 /**
1100 * Return whether this view's baseline will be considered the bottom of the view.
1101 *
1102 * @see #setBaselineAlignBottom(boolean)
1103 */
1104 public boolean getBaselineAlignBottom() {
1105 return mBaselineAlignBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 /**
1109 * Set a tinting option for the image.
1110 *
1111 * @param color Color tint to apply.
1112 * @param mode How to apply the color. The standard mode is
1113 * {@link PorterDuff.Mode#SRC_ATOP}
1114 *
1115 * @attr ref android.R.styleable#ImageView_tint
1116 */
1117 public final void setColorFilter(int color, PorterDuff.Mode mode) {
1118 setColorFilter(new PorterDuffColorFilter(color, mode));
1119 }
1120
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001121 /**
1122 * Set a tinting option for the image. Assumes
1123 * {@link PorterDuff.Mode#SRC_ATOP} blending mode.
1124 *
1125 * @param color Color tint to apply.
1126 * @attr ref android.R.styleable#ImageView_tint
1127 */
1128 @RemotableViewMethod
1129 public final void setColorFilter(int color) {
1130 setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
1131 }
1132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 public final void clearColorFilter() {
1134 setColorFilter(null);
1135 }
Philip Milneaac722a2012-03-26 13:30:26 -07001136
1137 /**
Adam Powell31049d72013-10-07 12:58:42 -07001138 * @hide Candidate for future API inclusion
1139 */
1140 public final void setXfermode(Xfermode mode) {
1141 if (mXfermode != mode) {
1142 mXfermode = mode;
1143 mColorMod = true;
1144 applyColorMod();
1145 invalidate();
1146 }
1147 }
1148
1149 /**
Philip Milneaac722a2012-03-26 13:30:26 -07001150 * Returns the active color filter for this ImageView.
1151 *
1152 * @return the active color filter for this ImageView
1153 *
1154 * @see #setColorFilter(android.graphics.ColorFilter)
1155 */
1156 public ColorFilter getColorFilter() {
1157 return mColorFilter;
1158 }
1159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 /**
1161 * Apply an arbitrary colorfilter to the image.
1162 *
1163 * @param cf the colorfilter to apply (may be null)
Philip Milneaac722a2012-03-26 13:30:26 -07001164 *
1165 * @see #getColorFilter()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 */
1167 public void setColorFilter(ColorFilter cf) {
1168 if (mColorFilter != cf) {
1169 mColorFilter = cf;
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001170 mColorMod = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 applyColorMod();
1172 invalidate();
1173 }
1174 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001175
Philip Milneaac722a2012-03-26 13:30:26 -07001176 /**
1177 * Returns the alpha that will be applied to the drawable of this ImageView.
1178 *
1179 * @return the alpha that will be applied to the drawable of this ImageView
1180 *
1181 * @see #setImageAlpha(int)
1182 */
1183 public int getImageAlpha() {
1184 return mAlpha;
1185 }
1186
1187 /**
1188 * Sets the alpha value that should be applied to the image.
1189 *
1190 * @param alpha the alpha value that should be applied to the image
1191 *
1192 * @see #getImageAlpha()
1193 */
1194 @RemotableViewMethod
1195 public void setImageAlpha(int alpha) {
1196 setAlpha(alpha);
1197 }
1198
1199 /**
1200 * Sets the alpha value that should be applied to the image.
1201 *
1202 * @param alpha the alpha value that should be applied to the image
1203 *
1204 * @deprecated use #setImageAlpha(int) instead
1205 */
1206 @Deprecated
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001207 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 public void setAlpha(int alpha) {
1209 alpha &= 0xFF; // keep it legal
1210 if (mAlpha != alpha) {
1211 mAlpha = alpha;
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001212 mColorMod = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 applyColorMod();
1214 invalidate();
1215 }
1216 }
1217
1218 private void applyColorMod() {
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001219 // Only mutate and apply when modifications have occurred. This should
1220 // not reset the mColorMod flag, since these filters need to be
1221 // re-applied if the Drawable is changed.
1222 if (mDrawable != null && mColorMod) {
1223 mDrawable = mDrawable.mutate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 mDrawable.setColorFilter(mColorFilter);
Adam Powell31049d72013-10-07 12:58:42 -07001225 mDrawable.setXfermode(mXfermode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
1227 }
1228 }
Adam Powell37419d72011-11-10 11:32:09 -08001229
Alan Viverettee10dd532013-12-12 19:19:51 -08001230 @Override
1231 public boolean isOpaque() {
1232 return super.isOpaque() || mDrawable != null && mXfermode == null
1233 && mDrawable.getOpacity() == PixelFormat.OPAQUE
1234 && mAlpha * mViewAlphaScale >> 8 == 255
1235 && isFilledByImage();
1236 }
1237
1238 private boolean isFilledByImage() {
1239 if (mDrawable == null) {
1240 return false;
1241 }
1242
1243 final Rect bounds = mDrawable.getBounds();
1244 final Matrix matrix = mDrawMatrix;
1245 if (matrix == null) {
1246 return bounds.left <= 0 && bounds.top <= 0 && bounds.right >= getWidth()
1247 && bounds.bottom >= getHeight();
1248 } else if (matrix.rectStaysRect()) {
1249 final RectF boundsSrc = mTempSrc;
1250 final RectF boundsDst = mTempDst;
1251 boundsSrc.set(bounds);
1252 matrix.mapRect(boundsDst, boundsSrc);
1253 return boundsDst.left <= 0 && boundsDst.top <= 0 && boundsDst.right >= getWidth()
1254 && boundsDst.bottom >= getHeight();
1255 } else {
1256 // If the matrix doesn't map to a rectangle, assume the worst.
1257 return false;
1258 }
1259 }
1260
Adam Powellb241b4c2011-11-10 19:48:23 -08001261 @RemotableViewMethod
Adam Powell37419d72011-11-10 11:32:09 -08001262 @Override
1263 public void setVisibility(int visibility) {
1264 super.setVisibility(visibility);
1265 if (mDrawable != null) {
1266 mDrawable.setVisible(visibility == VISIBLE, false);
1267 }
1268 }
1269
1270 @Override
Adam Powell6a939ae2011-11-10 14:11:51 -08001271 protected void onAttachedToWindow() {
Adam Powell37419d72011-11-10 11:32:09 -08001272 super.onAttachedToWindow();
1273 if (mDrawable != null) {
1274 mDrawable.setVisible(getVisibility() == VISIBLE, false);
1275 }
1276 }
1277
1278 @Override
Adam Powell6a939ae2011-11-10 14:11:51 -08001279 protected void onDetachedFromWindow() {
Adam Powell37419d72011-11-10 11:32:09 -08001280 super.onDetachedFromWindow();
1281 if (mDrawable != null) {
1282 mDrawable.setVisible(false, false);
1283 }
1284 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001285
1286 @Override
1287 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1288 super.onInitializeAccessibilityEvent(event);
1289 event.setClassName(ImageView.class.getName());
1290 }
1291
1292 @Override
1293 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1294 super.onInitializeAccessibilityNodeInfo(info);
1295 info.setClassName(ImageView.class.getName());
1296 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297}