自定义View高级知识点(一)
来源:互联网 发布:微信领取淘宝优惠券 编辑:程序博客网 时间:2024/06/07 01:00
Canvas基本Api速查
颜色混合模式(Alpha通道相关)
通过前面介绍我们知道颜色一般都是四个通道(ARGB)的,其中(RGB)控制的是颜色,而A(Alpha)控制的是透明度。
因为我们的显示屏是没法透明的,因此最终显示在屏幕上的颜色里可以认为没有Alpha通道。Alpha通道主要在两个图像混合的时候生效。
默认情况下,当一个颜色绘制到Canvas上时的混合模式是这样计算的:
(RGB通道) 最终颜色 = 绘制的颜色 + (1 - 绘制颜色的透明度) × Canvas上的原有颜色。
注意:
1.这里我们一般把每个通道的取值从0(ox00)到255(0xff)映射到0到1的浮点数表示。
2.这里等式右边的“绘制的颜色”、“Canvas上的原有颜色” 都是经过预乘了自己的Alpha通道的值。如绘制颜色:0x88ffffff,那么参与运算时的每个颜色通道的值不是1.0,而是(1.0 * 0.5333 = 0.5333)。 (其中0.5333 = 0x88/0xff)
使用这种方式的混合,就会造成后绘制的内容以半透明的方式叠在上面的视觉效果。
Paint.setXfermode模式
下表是各个PorterDuff模式的混合计算公式:(D指原本在Canvas上的内容dst,S指绘制输入的内容src,a指alpha通道,c指RGB各个通道),各种模式如下图所示。
onMeasure
真正进行测量的是 setMeasuredDimension
如果对View的宽高进行修改了,不要调用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); 要调用 setMeasuredDimension( widthsize, heightsize); 这个函数。
paint绘制图形
一个要点:绘制的基本形状由Canvas确定,但绘制出来的颜色,具体效果则由Paint确定
STROKE //描边
FILL //填充
FILL_AND_STROKE //描边加填充
1.圆角矩形
利用圆角矩形也可以绘制出椭圆
RectF rectF = new RectF(100, 100, 300, 300);mPaint.setColor(Color.BLACK);canvas.drawRect(rectF, mPaint);mPaint.setColor(Color.RED);canvas.drawRoundRect(rectF, 100, 50, mPaint);
2.椭圆
椭圆绘制可以理解为做一个矩形的内切圆,如果这是一个正方形那么绘制出来的就是一个圆形
RectF rectF = new RectF(100, 100, 400, 300);mPaint.setColor(Color.BLACK);canvas.drawOval(rectF, mPaint);
3.扇形
drawArc(RectF oval, float startAngle(开始角度0-360), float sweepAngle(扫过角度0-360), boolean useCenter(是否连接圆心),Paint paint)
// 使用中心 RectF rectF = new RectF(100, 100, 200, 200); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setColor(Color.GRAY); canvas.drawRect(rectF, mPaint); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.BLACK); canvas.drawArc(rectF, 0, 90, true, mPaint); // 不使用中心 rectF = new RectF(100, 300, 200, 400); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); // 填充 并描边 mPaint.setColor(Color.GRAY); canvas.drawRect(rectF, mPaint); mPaint.setStyle(Paint.Style.STROKE); // 仅描边 mPaint.setColor(Color.RED); canvas.drawArc(rectF, 0, -90, false, mPaint);
4.画一个圆饼图
public class PieChartView extends View { private Paint mPaint; private List<Percent> mPercentList; public PieChartView(Context context) { super(context); init(); } public PieChartView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PieChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(2); mPercentList = new LinkedList<>(); mPercentList.add(new Percent("1", 0.4f, Color.WHITE)); mPercentList.add(new Percent("2", 0.4f, Color.BLUE)); mPercentList.add(new Percent("3", 0.2f, Color.RED)); } @Override protected void onDraw(Canvas canvas) { RectF rectF = new RectF(100, 100, 400, 400); canvas.drawOval(rectF, mPaint); float surplus = 1.0f; // 剩余的范围 float startAngle = 0; Percent percent; for (int i = 0, size = mPercentList.size(); i < size; i++) { percent = mPercentList.get(i); if (percent.percent <= surplus) { surplus -= percent.percent; startAngle += percent.drawArc(mPaint, canvas, startAngle, rectF); } } } /** * 采用封装的思想 */ public static class Percent { String tag; float percent; int color; public Percent(String tag, float percent, int color) { this.tag = tag; this.percent = percent; this.color = color; } /** * 绘制 这个百分比 * * @param paint * @param canvas * @param startAngle * @param rectF * @return 返回绘制的角度大小 */ public float drawArc(Paint paint, Canvas canvas, float startAngle, RectF rectF) { int oldColor = paint.getColor(); Paint.Style oldStyle = paint.getStyle(); paint.setColor(color); paint.setStyle(Paint.Style.FILL); canvas.drawArc(rectF, startAngle, 360 * percent, true, paint); paint.setColor(oldColor); paint.setStyle(oldStyle); return 360 * percent; } }}
操作画布
操作画布,操作的都是坐标系,是对当前坐标系进行移动、旋转、缩放、错切等操作
操作画布只会影响接下来的绘画,而不会影响之前已经绘画完成的图像
1.移动画布
// 移动画布 canvas.translate(getWidth() / 2, getHeight() / 2); canvas.drawCircle(0, 0, 200, mPaint); canvas.drawCircle(0, 0, 180, mPaint); // 旋转画布 并画线 for (int i = 0; i < 36; i++) { canvas.drawLine(0, 180, 0, 200, mPaint); canvas.rotate(10); }
2.旋转画布
public void rotate(float degrees) { native_rotate(mNativeCanvasWrapper, degrees); } /** * 相对某点缩放 */ public final void rotate(float degrees, float px, float py) { translate(px, py); rotate(degrees); translate(-px, -py); }
看下图为相对某点进行缩放,图中的绘制顺序 1.红 2.黄 3.蓝 4.绿
RectF rectF = new RectF(100, 100, 200, 200); mPaint.setColor(Color.RED); canvas.drawRect(rectF, mPaint); canvas.translate(200,200); // 先将坐标系O移动到相对点P mPaint.setColor(Color.YELLOW); canvas.drawRect(rectF, mPaint); canvas.rotate(90);// 在相对点P处将坐标系O进行旋转 O-->o P-->p mPaint.setColor(Color.BLUE); canvas.drawRect(rectF, mPaint); canvas.translate(-200,-200);// 将旋转后的坐标系o中的p与P对齐,让以后的操作都仍然相对于P点 mPaint.setColor(Color.GREEN); canvas.drawRect(rectF, mPaint);
3.缩放画布
public void scale(float sx, float sy) { native_scale(mNativeCanvasWrapper, sx, sy); } /** * 相对于某点进行缩放,其相对原理与相对某点旋转相同 */ public final void scale(float sx, float sy, float px, float py) { translate(px, py); scale(sx, sy); translate(-px, -py); }
缩放比例(sx,sy)取值范围详解:
负值时,坐标系方向取反,scale(1,-1)这个操作将使得坐标系变为数学中常用坐标系
旋转,缩放,位移三者应用
// 移动画布 canvas.translate(getWidth() / 2, getHeight() / 2); mPaint.setColor(Color.BLUE); for (int j = 0; j < 10; j++) { canvas.drawCircle(0, 0, 200, mPaint); canvas.drawCircle(0, 0, 180, mPaint); canvas.rotate(j); // 旋转画布 并画线![enter description here][6] for (float i = j; i <= 360f; i += 10f) { canvas.drawLine(0, 180, 0, 200, mPaint); canvas.rotate(10); } canvas.scale(0.75f, 0.75f); }
4.错切(skew)
错切是在某方向上,按照一定的比例对图形的每个点到某条平行于该方向的直线的有向距离做放缩得到的平面图形。(度娘)
public void skew(float sx, float sy) { native_skew(mNativeCanvasWrapper, sx, sy); }
用法:
canvas.translate(getWidth()/2,getHeight()/2); RectF rectF = new RectF(0, 0, 100, 100); mPaint.setColor(Color.RED); canvas.drawRect(rectF, mPaint); canvas.skew(-1,0); // 向左倾斜45度 canvas.drawRect(rectF, mPaint);
效果图:
本文中很多内容学习自自定义View系列,非常感谢!同时还有一些自己发现的小tips。
- 自定义View高级知识点(一)
- [Android 知识点] 自定义View(一)
- 自定义View(一)
- 自定义view(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义view(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一)
- 自定义View(一) 初识自定义view
- android 自定义View知识点
- UCGUI添加按键功能
- Mybatis加载属性的优先级
- 自己想转型其他技术方向,搜集到课程学习资料.
- Tomcat容器等级
- Vim插件管理利器——Vundle
- 自定义View高级知识点(一)
- CodeForces 446B DZY Loves Modification 经典+贪心+更换遍历对象
- 祝大家2017鸡年愉快幸福
- 1280. Permutation
- 腐都两年小记
- Java反射实例
- 类型和运算
- android动画_属性动画
- 安卓微信自动抢红包插件优化和实现