Android自定义View——可在背景图和前景图显示遮罩效果的ImageView

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012964944/article/details/50560503
如果对android自定义view还不太属性,可以查看我之前写的文章《Android自定义View——基础知识篇

废话不多说,先上效果图


从图中可以看出,我们可以设置背景图或前景图的遮罩,而且遮罩范围可以设置为整张图片或非透明部分,另外,还可以设置遮罩的颜色。

实现的难点在于,遮罩范围可以设置为整张图片或非透明部分:
.遮罩范围为整张图片时,直接通过canvas.drawColor(),在图片上面绘制一层遮罩。
.遮罩为非透明部分时,则通过drawable.setColorFilter(),设置drawable对象的颜色滤镜。原理如下:
 
// 创建新的颜色矩阵
      ColorMatrix colorMatrix = new ColorMatrix(new float[]{
         a,b,c,d,e,
         f,g,h,i,j,
         k,l,m,n,o,
         p,q,r,s,t});

      // 已知一个颜色值ARGB,则经过下面的矩阵运算可得出新的颜色值
     /* int red   = a*R + b*R + c*R + d*R + e;
         int green = f*G + g*G + h*G + i*G + j;
         int blue  = k*B + l*B + m*B + n*B + o;
         int alpha = p*A + q*A + r*A + s*A + t;
      */

      // 设置图片滤镜
      getDrawable().setColorFilter(new ColorMatrixColorFilter(colorMatrix));

      绘图
      drawable.draw(canvas)

(要更深入了解图像颜色处理,可以查看这篇文章:http://www.cnblogs.com/menlsh/archive/2013/02/03/2890888.html

关键代码:
/**
 * 可在背景图和前景图显示遮罩效果的ImageView (前提设置了setClickable(true))
 *
 * @author huangziwei
 * 
 */
public class MaskImageView extends ImageView {

    // 遮罩的范围
    public static final int MASK_LEVEL_BACKGROUND = 1; // 背景图显示遮罩
    public static final int MASK_LEVEL_FOREGROUND = 2; // 前景图显示遮罩
    private boolean mIsIgnoreAlpha = true; // 是否忽略图片的透明度,默认为true,透明部分不显示遮罩

    private boolean mIsShowMaskOnClick = true; // 点击时是否显示遮罩,默认开启
    private int mShadeColor = 0x00ffffff; // 遮罩颜色(argb,需要设置透明度)

    private int mMaskLevel = MASK_LEVEL_FOREGROUND; // 默认为前景图显示遮罩

    ColorMatrix mColorMatrix = new ColorMatrix(); // 颜色矩阵
    ColorFilter mColorFilter;


    public MaskImageView(Context context) {
        this(context, null);
    }

    public MaskImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MaskImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs) {

        TypedArray a = getContext().obtainStyledAttributes(attrs,
                R.styleable.MaskImageView);


        mIsIgnoreAlpha = a.getBoolean(R.styleable.MaskImageView_is_ignore_alpha, mIsIgnoreAlpha);
        mIsShowMaskOnClick = a.getBoolean(R.styleable.MaskImageView_is_show_mask_on_click, mIsShowMaskOnClick);
        mShadeColor = a.getColor(R.styleable.MaskImageView_mask_color, mShadeColor);
        mMaskLevel = a.getInt(R.styleable.MaskImageView_mask_level, mMaskLevel);

        // 忽略透明度时的颜色矩阵
        float r = Color.alpha(mShadeColor) / 255f;
        r=r-(1 - r)*0.15f;
        float rr = (1 - r)*1.15f;
        setColorMatrix(new float[]{
                rr, 0, 0, 0, Color.red(mShadeColor) * r,
                0, rr, 0, 0, Color.green(mShadeColor) * r,
                0, 0, rr, 0, Color.blue(mShadeColor) * r,
                0, 0, 0, 1, 0,
        });

        a.recycle();
    }

    private void setColorMatrix(float[] matrix) {
        mColorMatrix.set(matrix);
        mColorFilter = new ColorMatrixColorFilter(mColorMatrix);
    }

    // all drawables instances loaded from  the same resource share a common state
    // 从同一个资源文件获取的drawable对象共享一个状态信息,为了避免修改其中一个drawable导致其他drawable被影响,需要调用mutate()
    // 因为背景图在draw()阶段绘制,所以修改了背景图状态后必须调用invalidateSelf()刷新
    private void setDrawableColorFilter(ColorFilter colorFilter) {
        if (mMaskLevel == MASK_LEVEL_BACKGROUND) {
            if (getBackground() != null) {
                getBackground().mutate();
                getBackground().setColorFilter(colorFilter);
                getBackground().invalidateSelf();
            }
        } else if (mMaskLevel == MASK_LEVEL_FOREGROUND) {
            if (getDrawable() != null) {
                getDrawable().mutate();
                getDrawable().setColorFilter(colorFilter);
                getDrawable().invalidateSelf();
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mIsIgnoreAlpha) { // 忽略透明度
            if (mIsShowMaskOnClick && isPressed()) {
                // 绘制遮罩层
                setDrawableColorFilter(mColorFilter);
            } else {
                setDrawableColorFilter(null);
            }
            super.onDraw(canvas);
        } else { // 不忽略透明度
            setDrawableColorFilter(null);
            if (mMaskLevel == MASK_LEVEL_BACKGROUND) { // 背景图
                if (mIsShowMaskOnClick && isPressed()) {
                    // 绘制遮罩层
                    canvas.drawColor(mShadeColor);
                }
                super.onDraw(canvas);
            } else { // 前景图
                super.onDraw(canvas);
                if (mIsShowMaskOnClick && isPressed()) {
                    // 绘制遮罩层
                    canvas.drawColor(mShadeColor);
                }
            }
        }

    }

    /**
     * view状态改变
     */
    @Override
    protected void drawableStateChanged(){
        super.drawableStateChanged();
        invalidate();
    }

    public boolean isIsIgnoreAlpha() {
        return mIsIgnoreAlpha;
    }

    public void setIsIgnoreAlpha(boolean mIsIgnoreAlpha) {
        this.mIsIgnoreAlpha = mIsIgnoreAlpha;
        invalidate();
    }

    public boolean isIsShowMaskOnClick() {
        return mIsShowMaskOnClick;
    }

    public void setIsShowMaskOnClick(boolean mIsShowMaskOnClick) {
        this.mIsShowMaskOnClick = mIsShowMaskOnClick;
        invalidate();
    }

    public int getShadeColor() {
        return mShadeColor;
    }

    public void setShadeColor(int mShadeColor) {
        this.mShadeColor = mShadeColor;
        // 忽略透明度时的颜色矩阵
        float r = Color.alpha(mShadeColor) / 255f;
        r=r-(1 - r)*0.15f;
        float rr = (1 - r)*1.15f;
        setColorMatrix(new float[]{
                rr, 0, 0, 0, Color.red(mShadeColor) * r,
                0, rr, 0, 0, Color.green(mShadeColor) * r,
                0, 0, rr, 0, Color.blue(mShadeColor) * r,
                0, 0, 0, 1, 0,
        });
        invalidate();
    }

    public int getMaskLevel() {
        return mMaskLevel;
    }

    public void setMaskLevel(int mMaskLevel) {
        this.mMaskLevel = mMaskLevel;
        invalidate();
    }

}

// res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="MaskImageView">

        <attr name="mask_level" format="enum">
            <enum name="background" value="1"/>
            <enum name="foreground" value="2"/>
        </attr>
        <!-- 设置了setClickable(true)才生效,默认开启遮罩-->
        <attr name="is_show_mask_on_click" format="boolean"/>
        <attr name="mask_color" format="color"/>
        <!--是否忽略图片的透明度,默认为true,透明部分不显示遮罩 -->
        <attr name="is_ignore_alpha" format="boolean"/>

    </declare-styleable>

</resources>


关于自定义样式,可以查看上篇文章《Android自定义View——自定义样式》。

相关代码我放在了github上:https://github.com/1993hzw/Androids , 接下来的项目代码我都会放在上面,争取做一个类型工具的库。
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页