转载请注意: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