CustomPaint class提供了让用户自定义widget的能力,它暴露了一个canvas,可以通过这个canvas来绘制widget,CustomPaint会先调用painter绘制背景,然后再绘制child,最后调用foregroundPainter来绘制前景,CustomPaint的定义如下
成都创新互联公司客户idc服务中心,提供温江服务器托管、成都服务器、成都主机托管、成都双线服务器等业务的一站式服务。通过各地的服务中心,我们向成都用户提供优质廉价的产品以及开放、透明、稳定、高性价比的服务,资深网络工程师在机房提供7*24小时标准级技术保障。
CustomPaint的绘制过程都将会交给CustomPainter来完成,CustomPainter是个抽象接口,在子类化CustomPainter的时候必须要重写它的 paint 跟 shouldRepaint 接口,可以根据自己的场景来选择性的重写 hitTest 跟 shouldRebuildSemantics 方法。
canvas--画布,真正的绘制是由canvas跟paint来完成的,画布提供了各种绘制的接口来绘制图形,除此以外画布还提供了平移、缩放、旋转等矩阵变换接口,画布都有固定大小跟形状,还可以使用画布提供的裁剪接口来裁剪画布的大小形状等等。
常用的绘制接口有 更多请查看官方文档
Paint---笔画,是用来设置在画布上面绘制图形时的一些笔画属性,如:颜色、线宽、绘制模式、抗锯齿等等。常用属性有 更多请查看官方文档
color : 设置画笔颜色
isAntiAlias : 设置画笔是否扛锯齿
shader : 着色器,填充形状或者画线时用到,如果没设置将会使用color
strokeWidth : 设置画笔画线宽度
style :绘制模式,画线或充满
下面这个例子来自于官方,通过 CustomPaint 画出了一个蓝天跟太阳出来
效果如下:
流式布局(Liquid)的特点(也叫"Fluid") 是页面元素的宽度按照屏幕分辨率进行适配调整,但整体布局不变。栅栏系统(网格系统),用户标签等。在Flutter中主要有Wrap和Flow两种Widget实现。
在介绍Row和Colum时,如果子widget超出屏幕范围,则会报溢出错误,在Flutter中通过Wrap和Flow来支持流式布局,溢出部分则会自动折行。
上述有很多属性和Row的相同,其意义其实也是相同的,这里我就不一一介绍了,主要介绍下不同的属性:
我们一般很少会使用Flow,因为其过于复杂,需要自己实现子widget的位置转换,在很多场景下首先要考虑的是Wrap是否满足需求。Flow主要用于一些需要自定义布局策略或性能要求较高(如动画中)的场景。Flow有如下优点:
我们对六个色块进行自定义流式布局:
实现TestFlowDelegate:
可以看到我们主要的任务就是实现paintChildren,它的主要任务是确定每个子widget位置。由于Flow不能自适应子widget的大小,我们通过在getSize返回一个固定大小来指定Flow的大小,实现起来还是比较麻烦的。
窗口小部件(Widget)可以在Paint之前应用Transform进行转换,通过Transform可以对widget进行平移、旋转、缩放等矩阵变换。不像RotatedBox在layout前就对Widget进行旋转操作,Transform是在Widget绘制前进行转换,这意味着在计算Widget的显示需要占用多少空间时,不会去考虑Transform变换。
例子
在垂直方向移动15个单位距离
例子
顺时针旋转45°
例子
放大1.5倍
仓库地址:
pub 地址:
修改 MainActivity.kt 让 MainActivity 继承 qiuxiang.android_window.AndroidWindowActivity :
创建 MainApplication.kt :
修改 AndroidManifest.xml 的 application 新增属性 android:name=".MainApplication" :
main.dart:
我们需要用 @pragma('vm:entry-point') 声明一个入口函数,默认函数名是 androidWindow ,当然你可以随意指定一个,只是调用 open 的时候需要同时指定参数 entryPoint: 。
android_window.dart:
浮窗 app 的写法就和我们平时写的 app 没什么区别了,如果需要支持窗口拖拽移动,则要在最外层使用 AndroidWindow 。
最终效果:
更完整的示例请参考:
主应用和浮窗都有 post 和 setHandler 方法用于发送消息以及设置监听处理函数。用法举例:
主应用发送消息到浮窗:
浮窗监听并处理主应用消息:
反过来同理。
ClipRect控件默认是通过限制子widget的绘制区域来达到裁剪的效果的,通过custom clipper,可以自定义裁剪的大小跟坐标
ClipRect的定义如下
ClipRect class默认是没有任何裁剪效果的,需要通过clipper参数告诉ClipRect如何去裁剪,clipper是个CustomClipper类型,CustomClipper是个抽象接口类,我们通过继承CustomClipper,重写 getClip 方法可以定义一个裁剪区域,通过重写 shouldReclip 方法来告诉ClipRect当一个新的clipper被设置了是否需要更新裁剪区域,譬如开始设置的clipper裁剪坐标是从(10,10)开始的,新设置的clipper裁剪坐标是(20,20),那么shouldReclip需要返回true来通知ClipRect更新裁剪区域。
下面这个例子从网络上加载一张图片,并且进行裁剪,裁剪坐标是(10,10) 裁剪的宽高是图片的宽高减去10
效果如下