Android自定义控件Android 自定义控件Android进阶知识

实现图片的滤镜效果

2016-04-04  本文已影响1529人  尹star

提到这个到不是因为要做照片处理软件的滤镜效果,而是开发过程中设计师每每只提供一张icon图标,然后说点击效果你自己用程序实现吧;或者产品经理过来说,用户头像加个点击效果吧。以往的开发过程中,设计师多半会提供两张icon图标,一张正常状态,一张选中状态,这样点击的时候会有一个动态的效果。而现在一张图去实现点击效果还真有点难为了,车到山前必有路,谁让我是老司机呢。
首先我印象中Imageview会有个透明度Alpha的属性,于是我最先想到用setAlpha()来改变图片的透明度,但实际效果并不好。后来在Stay的点拨下终于找到了比较好的解决方案,ImageView有一个setColorFilter()的API,完全适合当前场景。

  /**
     * 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有以上三种调用方式,可以直接传入色值和mode,mode缺省的默认值为PorterDuff.Mode.SRC_ATOP,具体各mode的效果可以参见http://blog.sina.com.cn/s/blog_5da93c8f01012pkj.html, setColorFilter还可以传入ColorFilter的子类。

ColorFilter有三个子类ColorMatrixColorFilter,LightingColorFilter,PorterDuffColorFilter,它的功能应该就是按照一定的规则改变图片的颜色,三个子类各有各的不同的改法规则,其中ColorMatrixColorFilter的改变法则就是ColorMatrix的改变规则,它是ColorMatrix的应用。LightingColorFilter 乘以第一个颜色的RGB通道,然后加上第二个颜色。每一次转换的结果都限制在0到255之间。PorterDuffColorFilter 可以使用数字图像合成的16条Porter-Duff 规则中的任意一条来向Paint应用一个指定的颜色。

我们就挑第一个ColorMatrixColorFilter来举例,前面已经说过,ColorMatrixColorFilter的改变法则就是ColorMatrix的改变规则,它是ColorMatrix的应用。ColorMatrix是Android源码中一个颜色矩阵类,通过对这个类的一系列操作,可以控制改变图片的色调明暗饱和度等,这也就是图片处理软件实现滤镜效果的原理。这个类把颜色定义为一个4*5的矩阵,如果用一个一纬数组表示就是这样:
[ 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; 
*/

这里是源码里的注释,已经解释的很清楚了,RGBA的运算公式也清晰明了,所以实际调用过程中,我们可以通过传入需要的参数来控制RGBA的值,进而改变图片的色彩。

/** 
* 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 
*/

这里是一张图片的默认色彩属性值,我们只需要根据需求去调校各参数值,就能实现图片的滤镜效果了。再回到最开始的诉求,我是想通过程序实现单张图片的点击效果,但是设计师只提供了一张图,那么我只需要在手指按下的时候去给当前图片加个滤镜,抬起时再移除即可。简单粗暴点,直接上代码。

/**
 * 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};

    /**
     * 改变色调
     */
    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();
        }
    }

我这里随便给出了几个滤镜效果的参数值,但是未经调教,有可能效果一塌糊涂,基本原理很简单了,又要说到onTouch事件了,按下去的时候显示滤镜效果图,抬起时移除滤镜显示原图,这样点击的时候就有了一个动态的selector效果了。如下图:

device-2016-04-06-004225.gif device-2016-04-06-004356.gif device-2016-04-06-004437.gif
参考资料:
http://blog.sina.com.cn/s/blog_5da93c8f01012pkj.htm
http://my.oschina.net/gavinjin/blog/208586
上一篇下一篇

猜你喜欢

热点阅读