android 图形库,Android Skia图形库

lzyprime 博客 (github)

创建时间:2020.12.17

qq及邮箱:2383518170

λ:

Skia 是Android、flutter底层的2D图形库。Skia 官网。

2D页面无非就是 图形(点、线、面),文字, 所以Skia设计也很简单:

新建Canvas, 画布,所有内容画在这上面

通过Canvas相关方法画出内容。一般名为drawxxx(), 同时要传入一个Paint, 也就是画笔样式。

通过Canvas相关方法裁剪画布,一般名为clipxxx()

内容定位,以Canvas左上角为(0, 0)点,向右向下建立(x, y)坐标系。

在官网可以直接体验这些API的C++版本,android和flutter无非是做一层包装,API大差不差。

用处:

自定义View。 不管是Android还是flutter想要自定义程度高就离不开直接操作Render层。大多数情况的确可以用现有的组件拼凑出想要的效果,但坏处就是损失很多没必要的计算和渲染,而且有些东西生写不出来。flutter有很多组件原生设计简单,然后留出canvas用来自定义样式。

设计UI时,大概估计一下有多费。尤其是flutter, 之前团队项目写出来的列表肉眼可见的掉帧。 我翻看这部分代码,发现大量的无用的组件嵌套,然后频繁的rebuild, 宽高很多写死,没有自适应能力。很多UI长一样却不复用,出现ItemXXXView1, ItemXXXView2这种东西。所以有一段时间的工作就是删代码,git记录我一个月添加了几百行然后删了几千行。

Canvas

draw

drawColor: 喷色,不需要传画笔。

drawRect: 画矩形Rect,需要左上角点的坐标和矩形宽高,同时传入一个Paint画笔样式

drawRoundRect: 类似drawRect, 不同是可以设置圆角,通过传入圆角的 x, y 偏移值

drawOval: 椭圆Oval,类似drawRect。

drawCicle: 圆Circle, 类似drawRect。

drawPath: 画线,需要传入Path线的路径和Paint画笔。

drawText: 渲染文字,需要传入文字,起始位置的坐标,Paint画笔(主要设置文字样式)。

clip

clipxxx: 裁剪画布,可以传 Path, Oval, Rect, Circle 等等

trans

translate(x, y): 平移到x, y。 作为新的原点

scale(x, y): 缩放

rotate: 旋转

save: 保存当前状态,一般在变换前调用

restore: 恢复现场,必须保证之前有save操作

Path

除了规则图形外,其他 点,线,面 都可以通过Path画出来。然后就变成了数学题。

点动成线,线动成面,面动成体, 当直线长度与画笔粗细相同,就相当于画了一个 点, 而 面 可以看作多根 线 并排的结果。

moveTo(x, y): 移动到指定坐标

lineTo(x, y): 从当前位置向 (x, y) 画直线。 获得线段(localX, localY) -> (x, y)

quadTo(x1, y1, x2, y2): 贝塞尔曲线。从当前位置经过 (x1, y1) 向 (x2, y2) 画平滑曲线

conicTo: 类似quadTo

addCircle、 addRect等等,添加现成图形

close: 当前点与起始点连接,形成闭合图形。

Paint

color, width: 颜色,粗细

style: 填充方式

fill: 实心

stroke: 镂空、描边

fontStyle: 字号,字体,字宽,字重等等属性。 原生C++里通过构造可绘制字符串(sk_sp)实现, android 封装进了Paint里。 flutter 封装进了 TextStyle。

filter|shader: colorFilter,maskFilter等等效果

BlendMode

用于处理两个元素A, B 相交时显示方式。

(A在B上, A在B下, A与B同级) * (交集, 并集, 异或集)。

984c30d7c8a4

1.png

实践

利用Path画圆角长方形。

圆角值 topLeft == bottomRight == 20, topRight == bottomLeft == 40

起始位置(20, 20)

宽 200, 高 100

void draw(SkCanvas* canvas) {

SkPaint paint;

paint.setAntiAlias(true);

paint.setStyle(SkPaint::kStroke_Style);

paint.setStrokeWidth(8);

SkPath path;

double startX = 20, startY = 20; // (startX, startY) 左上角

double endX = startX + 200, endY = startY + 100; // (endX, endY) 右下角

double topLeftRadius = 20, topRightRadius = 40;

// 移动起始点到左上角,并空出左上角圆角位置。 所以x坐标要+topLeftRadius

path.moveTo(startX + topLeftRadius, startY);

// 横向画线,同理空出右上角圆角位置

path.lineTo(endX - topRightRadius, startY);

// 右上角的圆角, 经过右上角(endX, startY) 向 (endX, startY + topRightRadius) 画曲线

path.quadTo(endX, startY, endX, startY + topRightRadius);

// 同理完成右边, 底边,左边的绘制,最后与起始点 (startX + topLeftRadius, startY) 闭合

// 右边

path.lineTo(endX, endY - topLeftRadius);

// 右下圆角

path.quadTo(endX, endY, endX - topLeftRadius, endY);

// 底边

path.lineTo(startX + topRightRadius, endY);

// 底边圆角

path.quadTo(startX, endY, startX, endY - topRightRadius);

// 左边

path.lineTo(startX, startY + topLeftRadius);

// 左上圆角

path.quadTo(startX, startY, startX + topLeftRadius, startY);

canvas->drawPath(path, paint);

}

984c30d7c8a4

2.png

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值