很多時候我們使用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) ); } }}