一、前言
大家可能很多地方要用到一个点击变暗效果的ImageView,之前我想了两种解决方案,但是这两种方法都不好,但是还是提一提吧。
方案一:把ImageView的background设置为我们要的图片,src就设置一个drawable(被点击之后换成50%灰度的一个drawable)
方案一的弊端就是为了达到这种效果,我们的src被占用了。
方案二:用两层ImageView,上面的ImageView的background或者src设置为一个【被点击之后换成50%灰度的一个drawable】
方案二的弊端就是增加了GPU的渲染速度,为了绘制一张图要绘制两层,完全没必要。
二、正文
最后我就想办法自定义了一个ImageView,就特意去看了View.java的源码(ImageView继承View),想看看View被点击之后是如何更换drawable不同状态的图片。
在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);
}
如果穿进去的参数pressed是true的话,首先会判断一下是否需要更新drawable的状态。然后就根据传进来的参数pressed做相应的drawable视图变更。
那么现在就很好办了,我们只要重写setPressed(boolean pressed)这个方法就行了,当传进来的pressed是true的时候我们就改变ImageView的背景图。
**
* Created by minghao_zl on 14-9-17.
* 公共的蒙版ImageView(点击变暗效果)
*/
public class MaskableImageView 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 MaskableImageView(Context context) {
super(context);
}
public MaskableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MaskableImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setPressed(boolean pressed) {
updateView(pressed);
super.setPressed(pressed);
}
/**
* 根据是否按下去来刷新bg和src
* created by minghao.zl at 2014-09-18
* @param pressed
*/
private void updateView(boolean pressed){
//如果没有点击效果
if( !touchEffect ){
return;
}//end if
if( pressed ){//点击
/**
* 通过设置滤镜来改变图片亮度@minghao
*/
this.setDrawingCacheEnabled(true);
this.setColorFilter( new ColorMatrixColorFilter(BG_PRESSED) ) ;
this.getBackground().setColorFilter( new ColorMatrixColorFilter(BG_PRESSED) );
}else{//未点击
this.setColorFilter( new ColorMatrixColorFilter(BG_NOT_PRESSED) ) ;
this.getBackground().setColorFilter(
new ColorMatrixColorFilter(BG_NOT_PRESSED));
}
}
}
其实很简单,我就在setPressed()方法里面根据传进来的参数pressed来处理视图改变的效果。updateView()方法里面也就是通过一个设置一个滤镜矩阵来改变灰暗度,我就不细说滤镜矩阵了。
~完了,不懂的可以留言噢,(*^__^*) 嘻嘻……