很多時候我們使用ImagView顯示圖片,無論是Gilde,Fresco等圖片顯示框架,比如設置中心更換頭像,網格相冊點擊預覽,選擇等情況,會遇到點擊變暗的交互需求。
- 源碼分析
我們想的辦法是自定義一個ImageView,當點擊圖片時,是不是有回調方法來同時改變圖片的濾鏡或者蒙版等。
特意去看了View.java的源碼(ImageView繼承View),想看看View被點擊之後是是否有回調函數可用。
View的onTouchEvent()方法
case MotionEvent.ACTION_DOWN:
mHasPerformedLongPress = false;
if (performButtonActionOnTouchDown(event)) {
break;
}
// Walk up the hierarchy to determine if we're inside a scrolling container.
boolean isInScrollingContainer = isInScrollingContainer();
// For views inside a scrolling container, delay the pressed feedback for
// a short period in case this is a scroll.
if (isInScrollingContainer) {
mPrivateFlags |= PFLAG_PREPRESSED;
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
// Not inside a scrolling container, so show the feedback right away
setPressed(true);
checkForLongClick(0);
}
break;
意思就是case: MotionEvent.ACTION_DOWN,按下去的時候事件發生時,檢測View是否被點擊了,如果點擊了就setPressed(true);把狀態標記爲已點擊
對應的case: MotionEvent.ACTION_UP,鬆開手的時候會檢測是否是unpressed,如果是就setPressed(false);把狀態標記爲未點擊。
setPress(boolean pressed)這個方法,定義如下
/**
* Sets the pressed state for this view.
*
* @see #isClickable()
* @see #setClickable(boolean)
*
* @param pressed Pass true to set the View's internal state to "pressed", or false to reverts
* the View's internal state from a previously set "pressed" state.
*/
public void setPressed(boolean pressed) {
final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED);
if (pressed) {
mPrivateFlags |= PFLAG_PRESSED;
} else {
mPrivateFlags &= ~PFLAG_PRESSED;
}
if (needsRefresh) {
refreshDrawableState();
}
dispatchSetPressed(pressed);
}
就是說View按下時會調用這個方法改變view的狀態,那麼我們就可以在這個方法中做文章,重寫這個方法。當參數是true時,使用顏色矩陣ColorMetrix來改變drawable的濾鏡,當參數是false時,還原圖像
/*點擊變暗效果的ImageView*/
public class MaskImageView extends ImageView {
private boolean touchEffect = true;
public final float[] BG_PRESSED = new float[] { 1, 0, 0, 0, -50, 0, 1, 0, 0, -50, 0, 0, 1, 0, -50, 0, 0, 0, 1, 0 };
public final float[] BG_NOT_PRESSED = new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 };
public MaskImageView(Context context) {
super(context);
}
public MaskImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MaskImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MaskImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void setPressed(boolean pressed) {
updateView(pressed);
super.setPressed(pressed);
}
/**
* 根據是否按下去來刷新bg和src
*
* @param pressed
*/
private void updateView(boolean pressed){
//如果沒有點擊效果
if( !touchEffect ){
return;
}
if( pressed ){
/**
* 通過設置濾鏡來改變圖片亮度
*/
this.setDrawingCacheEnabled(true);
this.setColorFilter( new ColorMatrixColorFilter(BG_PRESSED) ) ;
//此爲src,背景用getBackground()
this.getDrawable().setColorFilter( new ColorMatrixColorFilter(BG_PRESSED) );
}else{
this.setColorFilter( new ColorMatrixColorFilter(BG_NOT_PRESSED) ) ;
this.getDrawable().setColorFilter( new ColorMatrixColorFilter(BG_NOT_PRESSED) );
}
}
}