Android杂谈(8)关于自定义View的一些实践+遮罩理解

转载请注意:http://blog.csdn.net/wjzj000/article/details/52038664

我和一帮应届生同学维护了一个公众号:IT面试填坑小分队。旨在帮助应届生从学生过度到开发者,并且每周树立学习目标,一同进步!

 

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅… 
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入) 
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)

 

 

 

 

记录在前边:当我们继承View时无论是现有的控件还是ViewGroup等等,我们都会重写构造函数。他们的作用:

只继承含context参数的构造函数,只能通过java代码申明使用;实现Context context, AttributeSet attrs的构造函数可以在布局中申明使用;实现Context context, AttributeSet attrs, int defStyle的构造函数,可以通过名字看出,增入了style的使用。

自定义View如果说简单就是onMeasure(),onLayout(),onDraw();但是说难可能难在理解上吧...

很多技术书籍在讲解自定义View的时候,基本上都会提到重写onMeasure()。

简单记一下,让自己也有点印象.....兴许某天继承共产主义事业的时候就用到了呢。

关于讲解重写onMeasure()的时候:都会重点讲解EXACTLY和AT_MOST以及UNSPECIFIED三种测量模式。

关于AT_MOST模式,就是当控件使用wrap_content的时候测量模式要对这个家伙进行亲密接触。

关于EXACTLY模式,就是当控件使用固定值时(如100dp)或是match_parent时将使用这个测量模式。

 

在自定义View时,比如继承TextView。

想要这个自定义的View能够正常的设置layout_width和layout_height,就要重写onMeasure()。在这里,经过测试,只需要重写onMeasure(),调用父类的onMeasure()即可完成这个效果,不需要任何其他代码。在这里并没有任何关于EXACTLY和AT_MOST以及UNSPECIFIED的代码。

但是我们使用warp_content的时候会发现,实际效果是填充父布局的效果。所以在这里我们就是用了上文提到的测量模式:在测量方法中,通过获取测量模式,然后判断,当模式等于AT_MOST,对宽度进行相应的处理,最后通过setMeasuredDimension()将处理的宽高传入,完成对warp_content的处理。

实际上我们也会发现padding也是不支持的。所以我们同样要在onMeasure中考虑padding的情况,与此同时我们也要考虑onLayout中的情况。

 

 

8月24补充,一个开源圆角自定控件的分析。

首先上一个东西...之前我一直没整明白这玩意是什么规则,今天明白了。特定记录一下。

红线缩圈的是attr.xml文件下的自定义属性的前缀。其实这玩意没有规则,叫啥都行。当然这里叫啥,你就得在相应自定义控件的标签下的前缀写啥。

像这样:

蓝线缩圈是自定义控件的包名(一个简单的方式就是将蓝线部分换为res-auto),就像我们使用xmls:app一个道理。

那么接下来进入正题

首先在attr.xml中定义了名为RoundImageView的一些额外属性:

那么接下来就是在构造方法里拿到这些具体的属性。

紧接着就是初始化画笔,在这里关于圆角的绘制,很多书籍或是博客都会提到遮罩这个概念,具体的原理的解释,在这就不多bb了,其实我觉得这种东西就是意会的...因为我也不会(下文有关于遮罩的补充理解)。

关于onDraw()的过程.....

 

@Override
protected void onDraw(Canvas canvas) {
    // 创建遮罩图片和画布
    if (mDestBitmap == null) {
        mDestBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        mSrcBitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
        mDestCanvas = new Canvas(mDestBitmap);
        mSrcCanvas = new Canvas(mSrcBitmap);
    }
    // 获取imageview原先的图片
    super.onDraw(mDestCanvas);

    // 创建矩形,表示圆角矩形
    if (mRoundRectClip == null) {
        mRoundRectClip = new RectF(mBorderValue, mBorderValue,
                getWidth() - mBorderValue, getHeight() - mBorderValue);
    }
    // 绘制圆角矩形
    mSrcCanvas.drawRoundRect(mRoundRectClip,mCornerXValue,mCornerYValue,mNomalPaint);

    // 使用遮罩画笔扣除原图中的圆角矩形外面的部分
    mDestCanvas.drawBitmap(mSrcBitmap,0,0,mPaintClip);

    // 创建board的矩形
    if (mRoundRectBorder == null) {
        mRoundRectBorder = new RectF(mBorderValue / 2,
                mBorderValue / 2, getWidth() - mBorderValue / 2, getHeight() - mBorderValue / 2);
    }
    // 绘制board
    mDestCanvas.drawRoundRect(mRoundRectBorder, mCornerXValue, mCornerYValue, mPaintBoard);

    // 绘制最终的圆角带有board的图
    canvas.drawBitmap(mDestBitmap,0,0,mNomalPaint);
}

 

遮罩理解:

最常见的一张图,实话,第一次看我是懵逼的。我还是个孩子,为什么要给我看这个....

其实比较好理解,遮罩顾名思义是两个东西重叠在一起出现的效果。

黑色线圈起来的,Src表示一张图,Dst表示另一张图;而红色线圈起来的表示设置遮罩模式。啥叫模式?

 

paint.setXfermode( new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

 

 

 

 

 

代码是这么写的,而画线部分对应红色线圈起来的模式效果。

展示一个案例:

 

Canvas canvas = new Canvas(bitmap);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(mask, 0f, 0f, paint); 

 

 

 

 

 

这段代码的含义就是,在bitmap上重叠mask,用SRC_IN的模式展示重叠效果。

 

PorterDuff.Mode.CLEAR //清除画布上图像 

PorterDuff.Mode.SRC //显示上层图像 
PorterDuff.Mode.DST //显示下层图像 
PorterDuff.Mode.SRC_OVER //上下层图像都显示,上层居上显示 
PorterDuff.Mode.DST_OVER //上下层都显示,下层居上显示 
PorterDuff.Mode.SRC_IN //取两层图像交集部门,只显示上层图像 
PorterDuff.Mode.DST_IN //取两层图像交集部门,只显示下层图像 
PorterDuff.Mode.SRC_OUT //取上层图像非交集部门 
PorterDuff.Mode.DST_OUT //取下层图像非交集部门 
PorterDuff.Mode.SRC_ATOP //取下层图像非交集部门与上层图像交集部门 
PorterDuff.Mode.DST_ATOP //取上层图像非交集部门与下层图像交集部门 
PorterDuff.Mode.XOR //取两层图像的非交集部门

 

 

好的,先就这样了.....

 

 

 

 

 

 

希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:

https://github.com/zhiaixinyang/PersonalCollect 
https://github.com/zhiaixinyang/MyFirstApp

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值