提到這個(gè)到不是因?yàn)橐稣掌幚碥浖臑V鏡效果设联,而是開發(fā)過程中設(shè)計(jì)師每每只提供一張icon圖標(biāo)恕曲,然后說點(diǎn)擊效果你自己用程序?qū)崿F(xiàn)吧;或者產(chǎn)品經(jīng)理過來說飒筑,用戶頭像加個(gè)點(diǎn)擊效果吧片吊。以往的開發(fā)過程中,設(shè)計(jì)師多半會(huì)提供兩張icon圖標(biāo)协屡,一張正常狀態(tài)俏脊,一張選中狀態(tài),這樣點(diǎn)擊的時(shí)候會(huì)有一個(gè)動(dòng)態(tài)的效果肤晓。而現(xiàn)在一張圖去實(shí)現(xiàn)點(diǎn)擊效果還真有點(diǎn)難為了爷贫,車到山前必有路,誰讓我是老司機(jī)呢补憾。
首先我印象中Imageview會(huì)有個(gè)透明度Alpha的屬性漫萄,于是我最先想到用setAlpha()來改變圖片的透明度,但實(shí)際效果并不好盈匾。后來在Stay的點(diǎn)撥下終于找到了比較好的解決方案腾务,ImageView有一個(gè)setColorFilter()的API,完全適合當(dāng)前場景削饵。
/**
* Set a tinting option for the image.
*
* @param color Color tint to apply.
* @param mode How to apply the color. The standard mode is
* {@link PorterDuff.Mode#SRC_ATOP}
*
* @attr ref android.R.styleable#ImageView_tint
*/
public final void setColorFilter(int color, PorterDuff.Mode mode) {
setColorFilter(new PorterDuffColorFilter(color, mode));
}
/**
* Set a tinting option for the image. Assumes
* {@link PorterDuff.Mode#SRC_ATOP} blending mode.
*
* @param color Color tint to apply.
* @attr ref android.R.styleable#ImageView_tint
*/
@RemotableViewMethod
public final void setColorFilter(int color) {
setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
/**
* Apply an arbitrary colorfilter to the image.
*
* @param cf the colorfilter to apply (may be null)
*
* @see #getColorFilter()
*/
public void setColorFilter(ColorFilter cf) {
if (mColorFilter != cf) {
mColorFilter = cf;
mColorMod = true;
applyColorMod();
invalidate();
}
}
setColorFilter有以上三種調(diào)用方式岩瘦,可以直接傳入色值和mode,mode缺省的默認(rèn)值為PorterDuff.Mode.SRC_ATOP窿撬,具體各mode的效果可以參見http://blog.sina.com.cn/s/blog_5da93c8f01012pkj.html启昧, setColorFilter還可以傳入ColorFilter的子類。
ColorFilter有三個(gè)子類ColorMatrixColorFilter劈伴,LightingColorFilter箫津,PorterDuffColorFilter,它的功能應(yīng)該就是按照一定的規(guī)則改變圖片的顏色宰啦,三個(gè)子類各有各的不同的改法規(guī)則苏遥,其中ColorMatrixColorFilter的改變法則就是ColorMatrix的改變規(guī)則,它是ColorMatrix的應(yīng)用赡模。LightingColorFilter 乘以第一個(gè)顏色的RGB通道田炭,然后加上第二個(gè)顏色。每一次轉(zhuǎn)換的結(jié)果都限制在0到255之間漓柑。PorterDuffColorFilter 可以使用數(shù)字圖像合成的16條Porter-Duff 規(guī)則中的任意一條來向Paint應(yīng)用一個(gè)指定的顏色教硫。
我們就挑第一個(gè)ColorMatrixColorFilter來舉例叨吮,前面已經(jīng)說過,ColorMatrixColorFilter的改變法則就是ColorMatrix的改變規(guī)則瞬矩,它是ColorMatrix的應(yīng)用茶鉴。ColorMatrix是Android源碼中一個(gè)顏色矩陣類,通過對這個(gè)類的一系列操作景用,可以控制改變圖片的色調(diào)明暗飽和度等涵叮,這也就是圖片處理軟件實(shí)現(xiàn)濾鏡效果的原理。這個(gè)類把顏色定義為一個(gè)4*5的矩陣伞插,如果用一個(gè)一緯數(shù)組表示就是這樣:
[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]割粮。
/**
* 4x5 matrix for transforming the color+alpha components of a Bitmap.
* The matrix is stored in a single array, and its treated as follows:
* [ a, b, c, d, e,
* f, g, h, i, j,
* k, l, m, n, o,
* p, q, r, s, t ]
* * When applied to a color [r, g, b, a], the resulting color is computed as * (after clamping)
* R' = a*R + b*G + c*B + d*A + e;
* G' = f*R + g*G + h*B + i*A + j;
* B' = k*R + l*G + m*B + n*A + o;
* A' = p*R + q*G + r*B + s*A + t;
*/
這里是源碼里的注釋,已經(jīng)解釋的很清楚了媚污,RGBA的運(yùn)算公式也清晰明了舀瓢,所以實(shí)際調(diào)用過程中,我們可以通過傳入需要的參數(shù)來控制RGBA的值耗美,進(jìn)而改變圖片的色彩京髓。
/**
* Set this colormatrix to identity:
* [ 1 0 0 0 0 - red vector
* 0 1 0 0 0 - green vector
* 0 0 1 0 0 - blue vector
* 0 0 0 1 0 ] - alpha vector
*/
這里是一張圖片的默認(rèn)色彩屬性值,我們只需要根據(jù)需求去調(diào)校各參數(shù)值商架,就能實(shí)現(xiàn)圖片的濾鏡效果了朵锣。再回到最開始的訴求,我是想通過程序?qū)崿F(xiàn)單張圖片的點(diǎn)擊效果甸私,但是設(shè)計(jì)師只提供了一張圖诚些,那么我只需要在手指按下的時(shí)候去給當(dāng)前圖片加個(gè)濾鏡,抬起時(shí)再移除即可皇型。簡單粗暴點(diǎn)诬烹,直接上代碼。
/**
* Created by yx on 16/4/3.
*/
public class DiscolorImageView extends ImageView{
/**
* 變暗
*/
private final float[] SELECTED_DARK = new float[]
{1, 0, 0, 0, -80,
0, 1, 0, 0, -80,
0, 0, 1, 0, -80,
0, 0, 0, 1, 0};
/**
* 變亮
*/
private final float[] SELECTED_BRIGHT = new float[]
{1, 0, 0, 0, 80,
0, 1, 0, 0, 80,
0, 0, 1, 0, 80,
0, 0, 0, 1, 0};
/**
* 高對比度
*/
private final float[] SELECTED_HDR = new float[]
{5, 0, 0, 0, -250,
0, 5, 0, 0, -250,
0, 0, 5, 0, -250,
0, 0, 0, 1, 0};
/**
* 高飽和度
*/
private final float[] SELECTED_HSAT = new float[]
{(float) 3, (float) -2, (float) -0.2, 0, 50,
-1, 2, -0, 0, 50,
-1, -2, 4, 0, 50,
0, 0, 0, 1, 0};
/**
* 改變色調(diào)
*/
private final float[] SELECTED_DISCOLOR = new float[]
{(float) -0.5, (float) -0.6, (float) -0.8, 0, 0,
(float) -0.4, (float) -0.6, (float) -0.1, 0, 0,
(float) -0.3, 2, (float) -0.4, 0, 0,
0, 0, 0, 1, 0};
public DiscolorImageView(Context context) {
super(context);
this.setOnTouchListener(VIEW_TOUCH_DISCOLOR);
}
public DiscolorImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnTouchListener(VIEW_TOUCH_DISCOLOR);
}
public DiscolorImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnTouchListener(VIEW_TOUCH_DISCOLOR);
}
public OnTouchListener VIEW_TOUCH_DISCOLOR = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ImageView iv = (ImageView) v;
iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_HDR));
//iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_BRIGHT));
//iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_HDR));
//iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_HSAT));
//iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_DISCOLOR));
} else if (event.getAction() == MotionEvent.ACTION_UP) {
ImageView iv = (ImageView) v;
iv.clearColorFilter();
mPerformClick();
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
ImageView iv = (ImageView) v;
iv.clearColorFilter();
}
return true;
}
};
private void mPerformClick() {
DiscolorImageView.this.performClick();
}
}
我這里隨便給出了幾個(gè)濾鏡效果的參數(shù)值弃鸦,但是未經(jīng)調(diào)教绞吁,有可能效果一塌糊涂,基本原理很簡單了唬格,又要說到onTouch事件了家破,按下去的時(shí)候顯示濾鏡效果圖,抬起時(shí)移除濾鏡顯示原圖购岗,這樣點(diǎn)擊的時(shí)候就有了一個(gè)動(dòng)態(tài)的selector效果了汰聋。如下圖:
參考資料:
http://blog.sina.com.cn/s/blog_5da93c8f01012pkj.htm
http://my.oschina.net/gavinjin/blog/208586