ImageView源碼解析
前面看完了與Drawable有關的方法之後,今天我們再繼續。
其它方法解析3
1. 有關ImageView的顯示資源的異步設定
提到異步,先來看一個內部類ImageDrawableCallback:
private class ImageDrawableCallback implements Runnable {
private final Drawable drawable;
private final Uri uri;
private final int resource;
ImageDrawableCallback(Drawable drawable, Uri uri, int resource) {
this.drawable = drawable;
this.uri = uri;
this.resource = resource;
}
@Override
public void run() {
setImageDrawable(drawable);
mUri = uri;
mResource = resource;
}
}
可以看到,這是一個實現了Runnable接口的類,意味着這其中的部分操作會在一個新的線程中進行。我們看,run()方法中,主要有3個操作:
- 首先是將傳入的Drawable設定爲當前ImageView的顯示內容。
- 接着是設置。
- 最後一步則是設置資源ID。
當然,構造方法中的操作也是一樣的。
很明顯,這個類與當前ImageView的顯示資源設置有關。
僅僅知道定義可能並沒有什麼,再來看這個類在哪裏起作用:
可以看到,ImageView中一共有三處調用,分別來看:
1.1 異步設置Icon圖標
public Runnable setImageIconAsync(@Nullable Icon icon) {
return new ImageDrawableCallback(icon == null ? null : icon.loadDrawable(mContext), null, 0);
}
其中,loadDrawable()是Icon類中的一個方法。作用和方法名稱一樣,就是加載Drawable,並初步設置其顏色渲染相關的值與渲染模式等。
public Drawable loadDrawable(Context context) {
final Drawable result = loadDrawableInner(context);
if (result != null && (mTintList != null || mTintMode != DEFAULT_TINT_MODE)) {
result.mutate();
result.setTintList(mTintList);
result.setTintMode(mTintMode);
}
return result;
}
我們看到,如果傳入的icon對象不爲空,則將加載得到的對象傳入了ImageDrawableCallback的構造器中,並賦值給mDrawable。的確,這裏的Drawable是與圖標有關係的。
既然提到到了Icon,那略微看一下:
一般來說,對於icon我們接觸最多的就是Manifest文件中關於application中的聲明,比如:
很明顯,這裏的icon屬性指的是【APP】的【啓動圖標】,也就是圖形化的程序的起點。
額外再多說一點,其實Activity中也是可以添加icon屬性的:
這裏的圖標主要適用於在某些特殊情況下,我們需要爲我們的apk設置多個執行入口,也就是安裝後在應用程序列表中出現多個ICON圖標,各個ICON是APP不同模塊的入口點,並且各個模塊運行在不同的進程中。特別注意不同的進程這一點,Activity有一個重要的屬性process,這個屬性就是指定Activity運行時所在的進程專用的。
===> 通過爲Activity設定不同的progress與icon我們可以爲當前的程序設定不同的入口與不同的啓動圖標。
1.2 通過id,異步設置圖像資源
public Runnable setImageResourceAsync(@DrawableRes int resId) {
return new ImageDrawableCallback(getContext().getDrawable(resId), null, resId);
}
通過id獲取到Drawable對象以後,在進行異步設置。
1.3 通過Uri,異步設置圖像
public Runnable setImageURIAsync(@Nullable Uri uri) {
if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
Drawable d = uri == null ? null :getDrawableFromUri(uri);
if (d == null) {
// Do not set the URI if the drawable couldn't be loaded.
uri = null;
}
return new ImageDrawableCallback(d, uri, 0);
}
return null;
}
通過uri加載得到Drawable對象後,只要不爲空,則通過ImageDrawableCallback異步設置好資源圖像。
2. ImageView的基線BaseLine
在筆記(一)中,我們瞭解到ImageView有一個成員變量叫做:mBaseline
private int mBaseline = -1;
這個BaseLine指的是視圖內基線的偏移量,也就是基線位置到ImageView頂部的距離 。來看代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#faf"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#000"
android:text="baseline效果展示"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baseline="50dp"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
上述佈局的展示效果如下圖所示:
很明顯我們把ImageView的bsaeline屬性設置爲50dp。而其左側的TextView恰恰距離整個視圖的頂端50dp。
當我們分別把
android:baseline="50dp"
的數值更改爲30dp與0dp時,我們再來看效果:
很明顯可以看出:
- 當值爲0dp即不設定基線值時,ImageView的頂端高度是緊貼其左側TextView底邊高度的
- 而在設置爲具體值,栗子當中爲30dp 、50dp時,imageview的頂端與父佈局平齊,而其左側TextView的頂邊距離ImageView頂端的差距則爲我們的設定值30dp 、50dp。
那麼這個屬性不在多說。
再來看另一個與之相關的成員變量
private boolean mBaselineAlignBottom = false;
可見這個布爾型變量的取值僅爲true與false。來看效果,先將上述佈局改成如下所示,即添加【android:baselineAlignBottom=”true”】
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baseline="0dp"
android:baselineAlignBottom="true"
android:src="@mipmap/ic_launcher"/>
效果變成了這樣:
與前面的”0dp”效果圖相比較,很明顯可以看出,左側TextView的底部與ImageView底端平齊。
因此可知:android:baselineAlignBottom屬性,是確定當前佈局的底部基線是否以ImageView爲準。
爲了驗證這個說法,我們再舉一個例子:
將佈局改爲:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#faf"
android:baselineAligned="true"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAlignBottom="true"
android:src="@mipmap/ic_launcher"/>
<ImageView
android:baseline="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
</LinearLayout>
我們這次用兩個ImageView舉例子。其中一個設定了android:baselineAlignBottom屬性,另一個與基線相差10dp。來看效果:
很明顯,右側ImageView的頂部距離設定了【baselineAlignBottom=”true”】的ImageView底部,相差10dp。
知道了定義後,我們再來看ImaeView中相應的方法:
首先是獲取與設置BaseLine的兩個方法:
2.1
public int getBaseline() {
if (mBaselineAlignBottom) {
return getMeasuredHeight();
} else {
return mBaseline;
}
}
2.2
public void setBaseline(int baseline) {
if (mBaseline != baseline) {
mBaseline = baseline;
requestLayout();
}
}
接下來是設定BaselineAlignBottom的兩個方法:
2.3
public void setBaselineAlignBottom(boolean aligned) {
if (mBaselineAlignBottom != aligned) {
mBaselineAlignBottom = aligned;
requestLayout();
}
}
2.4
public boolean getBaselineAlignBottom() {
return mBaselineAlignBottom;
}
不必過多解釋,大家自然能懂。