【騰訊Bugly乾貨分享】Android ImageView 正確使用姿式

本文來自於騰訊bugly開發者社區,未經做者贊成,請勿轉載,原文地址:http://dev.qq.com/topic/5832602d7196970d65901d76java

導語

本文主要介紹了ImageView的相關重要方法,從源碼角度剖析了一些容易使人混淆或百思不得其解的問題。android

1、正確合理使用ImageView 的src 和background

src :爲ImageView 原圖內容,存放原圖大小,不會被拉伸;微信

background:爲Imageview的背景,會根據ImageView給定的長寬進行拉伸;app

在ImageView中,能夠同時設置src和background屬性(爲了減小繪製,能夠根據使用場景來設置相應屬性); 因爲src中存放的是原圖大小,若是須要對其縮放,就須要使用android:scaleTyle這個屬性(scaleType 只對src屬性有效),另外還能夠對background設置透明度。框架

2、正確設置Imageview的透明度

設置ImageView的透明度有啥正確不正確的,如直接就mImageView.setAlpha(100),不就好了嗎?(答案是不肯定,後續分析異步

ImageView 設置透明度主要有如下三種方法:函數

  1. setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) (View提供工具

  2. setAlpha(int alpha) (已經標記爲@Deprecatedthis

  3. setImageAlpha(int alpha) (API>=16spa

其中,setImageAlpha內部調用setAlpha(int alpha)方法,查看API可知,setAlpha 主要是針對image而言,使用setImageView,一方面在命名上更爲貼切與View中的setAlpha方法區分,同時作好兼容性,目前只能使用在API>=16的場景。

另外, 像Drawable 和Paint中的都是調用setAlpha(int alpha)

在本節前就提了一個問題:直接使用mImageView.setAlpha(100),來設置ImageView的透明度是否正確?

正確答案是

  • android:src在設置ImageView的setAlpha(int alpha)時,起做用;
  • android:background在設置ImageView的setAlpha(int alpha)時,不起做用。

爲何呢?

在前面介紹中,已經指出ImageView中的setAlpha(int alpha)方法是針對image有效的,想弄清就直接看源碼:

(1)setAlpha(int alpha)方法

圖1 ImageView 的setAlpha()

(2)經過applyColorMod方法可知,ImageView.setAlpha(int alpha)方法,是經過Drawable.setAlpha(int alpha)實現的

圖2 ImageView的applyColorMod()

那麼mDrawable 是怎樣獲得的了:

圖3 ImageView構造函數 獲取src設置的圖片

setImageDrawable(Drawable d) 中調用 updateDrawable(Drawable d),而mDrawable 正是在updateDrawable(Drawable d)中賦值的:

圖4 ImageView的updateDrawable()方法

如今知道爲何有時候ImageView.setAlpha(int alpha)沒起做用了吧。

(3)在applyColorMod()中爲何使用Drawable.mutate()方法

直接引用Drawable.mutate()的JavaDoc:

Make this drawable mutable. This operation cannot be reversed. A mutable drawable is guaranteed to not share its state with any other drawable. This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification.Calling this method on a mutable Drawable will have no effect.

上述解釋的很清楚,一個drawable若是使用了mutate()方法,那麼對這個drawable屬性(包括設置drawable的透明度)修改將不會共享。

mImageView.setBackgroundDrawable(mDrawable);
mImageView.getBackground().setAlpha(100);

上述代碼有問題嗎?

「確定沒有額,經過這種方式透明度沒有問題額,親試可用」。若是你所使用的mDrawable是圖片資源(ColorDrawable 中使用了mutate方法),並且多處使用,你就會發現,其餘地方透明度也變了。

上述代碼正確寫法:

mImageView.setBackgroundDrawable(mDrawable.mutate());
mImageView.getBackground().setAlpha(100);
(4)總結

經過上面的分析可知,設置ImageView的透明度,坑仍是至關多的,目前來看使用View提供的setAlpha(float alpha)更好。

3、正確設置ImageView的前景(foreground)

有時候設計須要在ImageView 上面覆蓋一層(如灰色),面對這樣的需求時,要區分是靜態的ImageView仍是異步的ImageView (使用後臺回包數據)。

(1)靜態ImageView (此場景基本不多,設計切圖便可)

合理使用src (前景)和background(背景)就能夠實現

(2)異步ImageView

此就須要使用ImageView的前景(View 提供了一個setForeground(Drawable foreground))

圖5 View的setForeground()方法

圖 6 view的構造函數中mForegroundInfo對象建立

根據上述源碼可知,若是ImageView要使用setForeground()方法,必須保證targetSdkVersion>=23。

若是此時要在targetSdkVersion<23狀況使用,就必須本身去實現,好在afc框架中ExtendImageView已經考慮到這種狀況,已經實現了setForeFround()方法。

4、正確使用ImageView的「android:adjustViewBounds」

adjustViewBounds的介紹以下:

Set this to true if you want the ImageView to adjust its bounds to preserve the aspect ratio of its drawable.

Note:If the application targets API level 17 or lower, adjustViewBounds will allow the drawable to shrink the view bounds, but not grow to fill available measured space in all cases.This is for compatibility with legacy MeasureSpec and RelativeLayout behavior.

設置View的最大高度,單獨使用無效,須要與setAdjustViewBounds一塊兒使用;若是想設置圖片固定大小,又想保持圖片寬高比,須要以下設置:

  1. 設置setAdjustViewBounds爲true;

  2. 設置maxWidth、MaxHeight;

  3. 設置設置layout_width和layout_height爲wrap_content

5、正確使用ImageView的「android:scaleType」

如前所說,ImageView的「android:scaleType」屬性是對src纔有效的,以下圖所示,須要對下面原圖進行縮放控制,效果以下:

(1)原圖

(2)使用ScaleType.CENTER_CORP

設計大大以爲不合理,要是圖片總體能下來一點點就行了,查看一遍ScaleType,能到達這樣效果的只有FIT_XY,那就試試看

(3)使用ScaleType.FIT_XY

圖片確實下移了,可是圖卻明顯的被拉長了

(4)使用ScaleDrawable.CROP_START

ScaleDrawable類是afc框架中提供了一個專門處理Drawable scale的類,在ImageView的ScaleType的基礎上額外提供了11中裁剪方式:

(1)CROP_CENTER
(2)CROP_START
(3)CROP_END
(4)FIT_CENTER
(5)FIT_START
(6)FIT_END
(7)MATCH_WIDTH_TOP
(8)MATCH_WIDTH_BOTTOM
(9)MATCH_WIDTH_CENTER
(10)CENTER
(11)CROP_BY_PIVOT
(5)XML設置android:scaleType="fitXY"屬性

xml中設置scaleType屬性

java代碼中設置ScaleDrawable.CROP_START屬性

看到上述代碼,有人可能以爲很疑惑,既然在java代碼中設置了ScaleDrawable.CROP_START屬性,爲何XML中還要設置「android:scaleType="fitXY」,可否不設置或者設置其餘屬性。

答案是否認的,若是要保證ScaleDrawable.CROP_START屬性設置成功,在xml中必定要設置「android:scaleType="fitXY」,緣由以下:

1)經過ScaleDrawable設置scaleType

setScaleType()方法

2)在updateDrawMatrix()中更新目的寬高 (dstWidth和dstHeight)

updateDrawMatrix()方法

能夠看到,若是要ScaleDrawable.CROP_START屬性設置起做用,那個getBounds()方法獲取必定要準確。

3)經過查看ImageView中的configBounds()方法可知,在dwith和dheight(原圖Drawable的寬高)都不爲0的狀況下,若是要使用vwidth和vheight,則ImageView的ScaleType必須設置爲ScaleType.FIT_XY

configBounds()方法

最後

本人能力有限,分析可能不到位或錯誤的地方,若是發現,請告知謝謝!


更多精彩內容歡迎關注bugly的微信公衆帳號:

騰訊 Bugly是一款專爲移動開發者打造的質量監控工具,幫助開發者快速,便捷的定位線上應用崩潰的狀況以及解決方案。智能合併功能幫助開發同窗把天天上報的數千條 Crash 根據根因合併分類,每日日報會列出影響用戶數最多的崩潰,精準定位功能幫助開發同窗定位到出問題的代碼行,實時上報能夠在發佈後快速的瞭解應用的質量狀況,適配最新的 iOS, Android 官方操做系統,鵝廠的工程師都在使用,快來加入咱們吧!

相關文章
相關標籤/搜索