http://mp.weixin.qq.com/s/Rg213sQQ2ge4ARRzzxH4pw
看到一篇很使用的文章,想記錄下來,已標註轉載,莫怪!
mageView是大家用的非常多的控件之一,其相比於其他控件多了一個src屬性。我們平時在其中顯示的圖片往 往需要跟隨外部的變化切換圖片,這個時候我們一般會選擇用多張圖片來實現,如果變化後的圖片和原圖很類似,只是更改了顏色我們完全沒有必要去弄張新圖片 來,今天就來教大家如何實現這種情況的需求。
如何使用Imageview的問題我就不再多說了,現在我們要實現下面這樣一個Imageview:
一個圓形的Imageview,但是圓形的圖片顏色和中間的那個src圖片和其顏色都是可以變化的,比如這個是一個安全類的app,在掃描到有病毒的時候會 根據病毒的類型變化成不同的樣式。現在我們假定有3中狀態:無病毒、低風險病毒、高風險病毒,分別對於上面的三個狀態。對於這樣一個情況,你可能會使用多 張圖片來實現,這樣帶來的後果就是增加項目的工作量和app的大小。我們如何使用最少的圖片來實現呢?
使用background加src來實現
你可能最先想到的是分兩個部分,第一個是圓形的純色部分使用背景來實現,中間使用圖片來實現。我們照着這個思路來實現第一種效果,打開手機開發者選項裏面的過度繪製,來看看層級:
過度繪製的顏色從低到高分別是:藍色-綠色-淡紅-紅色,分別對應x1-x2-x3-x4的繪製次數。很明顯我們這裏存在兩層的繪製問題。這麼我們的佈局文件是這樣的:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imgv_toHint"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
android:background="@drawable/imgv_bg"
android:padding="30dp"
android:scaleType="centerInside"
android:src="@drawable/center_icon" />
</RelativeLayout>
這裏的Imageview分別設置了一個背景和一個圖片,那麼我們如何根據狀態來設置對應的狀態呢?來看java代碼部分:
imgv_toHint = (ImageView) findViewById(R.id.imgv_toHint);
LightingColorFilter bFilter = new LightingColorFilter(Color.TRANSPARENT, getResources().getColor(R.color.imgv_bg_yellow));
imgv_toHint.getBackground().setColorFilter(bFilter);
LightingColorFilter iFilter = new LightingColorFilter(Color.TRANSPARENT, getResources().getColor(R.color.src_bg_second));
imgv_toHint.getDrawable().setColorFilter(iFilter);
運行效果:
運行之後就可以看到和第二種效果是一樣的,這種方式有點略屌。使用了一個ColorFilter來對圖像進行處理,其中ColorFilter是一個抽象的類,不能直接來使用,需要使用其子類,他的子類有3個: LightingColorFilter、 ColorMatrixColorFilter、PorterDuffColorFilter;具體的使用我這裏就不過多的展開了,有興趣的同學可以深入的學習下,對處理圖片是非常有用的。當然還可以使用圖片中的各種tint屬性來實現,這裏就不再具體的演示如何實現了。
使用layer-list加level-list來實現
layer-list:其實質是給其中定義的item中的圖片按照順序一張張的繪製上去,默認是繪製一樣的大小,但是我們可以指定偏移量來達到不一樣的大小。
level-list:其實質是定義多張圖片對應多個狀態(使用int值來表示),在代碼中我們設置不同的狀態來控制顯示不同的圖片。
我們來看xml中的代碼:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imgv_toHint" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerInParent="true" android:src="@drawable/level_icon" /> </RelativeLayout>
來看看level_icon文件:
<?xmlversion="1.0" encoding="utf-8"?>
<level-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/layer_bg_first"
android:maxLevel="1"/>
<item
android:drawable="@drawable/layer_bg_secend"
android:maxLevel="2"/>
<item
android:drawable="@drawable/layer_bg_third"
android:maxLevel="3"/>
</level-list>
來看看其中一個layer-list:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="160dp"
android:height="160dp"
android:drawable="@drawable/imgv_bg_first" />
<item
android:width="100dp"
android:height="100dp"
android:drawable="@drawable/center_icon_first"
android:left="30dp"
android:top="30dp" />
</layer-list>
在代碼中我們可以這樣使用:
imgv_toHint = (ImageView) findViewById(R.id.imgv_toHint);
imgv_toHint.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imgv_toHint.getDrawable().setLevel(level = level >= 3 ? 1 : ++level);
}
});
獲取到drawable對象,然後設置其level系統就自動更換圖片了
這 種方式可以做到最少的代碼來控制圖片的更換,用一個變量來控制圖片自動顯示,使代碼非常的整潔,但是其也有一個不好的地方就是可能會增加圖片的數量。具體 的取捨需要根據具體的項目來考慮。當然我們也可以結合tint屬性和colorfilter來減少圖片的數量,但是又增加了代碼的數量。這種方式也存在過 度繪製的問題。
說了這麼多,過度繪製的問題還是沒能解決,其根本原因是我們還沒有給他們做到一張圖片來顯示。如果要做到一張圖片顯示又不 過多的引入圖片的數量,我們可以使用一個bitmap對象來繪製一張圖片然後設置到imageview上面去。因爲bitmap在繪製的時候不管是多麼復 雜,其也算是一層view。利用這個思路,我們來減少過度繪製的問題。
去掉過度繪製的問題
這種方式就不能夠在xml文件中直接設置src圖片了,因爲前面我們知道這種方式設置的話是行不通的。那麼我們只能在代碼中來設置,我們可以給資源文件中的layer-list轉化爲一張圖片,然後設置到imageview上面,這樣的話多了一層轉化少了一層繪製。
來看java中的代碼:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imgv_toHint = (ImageView) findViewById(R.id.imgv_toHint); Drawable src = getDrawable(R.drawable.layer_bg_secend); imgv_toHint.setImageBitmap(drawable2Bmp(src)); } private Bitmap drawable2Bmp(Drawable drawable) { Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap; }
這裏我們定義了一個drawable轉爲Bitmap的方法,給資源中的drawable對象轉化爲一張bitmap圖片,然後設置到imageview上面。