【Android_View】ImageView源碼簡析筆記(五)

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>

上述佈局的展示效果如下圖所示:
50dp
很明顯我們把ImageView的bsaeline屬性設置爲50dp。而其左側的TextView恰恰距離整個視圖的頂端50dp。
當我們分別把

android:baseline="50dp"

的數值更改爲30dp與0dp時,我們再來看效果:
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;
    }

不必過多解釋,大家自然能懂。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章