Flutter中自定义组件一般有两种方式:
成都创新互联公司致力于互联网网站建设与网站营销,提供成都网站设计、成都网站建设、网站开发、seo优化、网站排名、互联网营销、重庆小程序开发公司、公众号商城、等建站开发,成都创新互联公司网站建设策划专家,为不同类型的客户提供良好的互联网应用定制解决方案,帮助客户在新的全球化互联网环境中保持优势。
CustomPaint继承自SingleChildRenderObjectWidget,即它可以在通过嵌套引入到widget树中,并且可以有一个child子widget。它的构造方法如下:
painter和foregroundPainter需要接收CustomPainter对象,是CustomPaint核心。CustomPainter是进行UI绘制的核心类,绘制时, CustomPaint 首先在画布上调用 painter绘制 , 然后再绘制它的 child Widget, child 绘制完成后再调用 foregroundPainter 进行绘制。
size属性标识绘制区域大小,但当CustomPaint有child,该属性将会忽略,而使用child的大小为绘制区域大小。
isComplex和willChange用于控制绘制层缓存处理的,这里暂不讨论。
可实现CustomPainter子类进行UI绘制
实现paint方法进行真正的绘制,canvas是画布对象,size是绘制区域,是从CustomPaint中size属性传递得到的。绘制过程与Android原生开发十分类似,连API都十分相像,这点对熟悉Android原生开发者真是太友好了。
Paint对象是画笔对象,就是绘图工具,我们可以设置画笔的颜色、粗细、是否抗锯齿、笔触形状以及作画风格等,通过这些属性我们可以很方便的来定制自己的UI效果,在绘制的过程中可以定义多个画笔,以便实现多种风格图形的集合。
根据需求选择合适的画笔属性,完成你的绘制。
Canvas是绘制的画布,它包含了很多绘制方法,可以绘制出各种形状的图形。需要注意的是,画布是应用所有控件都在使用的, 所以通过这个画布其实是可以绘制充满屏幕的内容的,每次绘制都应该限制在本控件的区域(Size)内, 以免绘制覆盖到其他组件。
下面介绍下Canvas的绘制方法:
PointMode是个枚举
p1、p2为线段两个端点
Rect定义矩形的大小位置,有多种构造方式:
RRect描述圆角矩形,他通过Rect和Radius来构造
画圆比较简单,c表示圆心位置,radius是半径。
椭圆使用外接矩形确定大小位置,rect就是外接矩形。
绘制弧形,先确定弧形对应的椭圆,同样地用外接矩形rect确定椭圆,然后根据起始点和结束点角度来确定那一段弧度,startAngle,sweepAngle分别代表起始和结束点角度,角度用弧度表示法。
useCenter表示是否连接闭合形状,userCenter = false表示不闭合,即画一段弧线,userCenter = true表示闭合,即绘制一个扇形。
绘制路径,关键在于构建路径Path,可以直接new Path对象,然后通过path方法可以连接出图形,path关键方法如下:
还有其他方法,有兴趣可以查看API。
我是初学者小白,所以很多看法不深,理解也不够透彻。但是很适合小白们一起从低角度往高处探索。文中有错误的,感谢指正,一起进步。
趁着假期做一个Flutter的地图功能,因为后端选用了百度地图,所以前端没得挑。找了遍插件,并没有现成可用的。(不过发现了百度官方也自开发Flutter插件,目前功能只有一个获取本地位置信息,后期会继续增加吧?很期待!)
参考帖子:
这个实际上跟功能之间没太大关系,只是我按照个人摸索的过程来写。
当对一个“领域/知识块”完全不懂的时候,360°的方向都不确定的话。先了解基础概念,有利于你确定自己的摸索方向。
参考帖子:
中间我跳过了几十,上百个帖子的摸索过程。这个才是关键能够真正做事的参考。
因为百度的sdk还算是很完善的,所以一旦出问题,都会有对应的报错提示。
我是使用flutter插件:permission_handler,来解决安卓的动态授权问题,用法简单而且设计合理。
这个错误直接来看,就是签名有问题。怎么查看SHA1码和包名,这里不多说,网上有极其多的方法,百度Sdk开发指南里也有。没那么复杂,也没那么麻烦。按照流程操作就是对的。
实在不放心?跟我一样,flutter打包后,把apk反过来解SHA1码不就行了?
参考帖子:
红色框框基本就是帖子讲解的那样。
蓝色框框见下图:release标签里好像是自己设置了。所以debug标签里面,箭头指向的位置,是我多设置的一个参数。
uid: -1 appid -1 msg: httpsPost failed,IOException:Unable to resolve host "api.map.baidu.com": No address associated with hostname
这一步我是哭笑不得,一开始老是和问题(2)混淆,导致浪费很多时间。仔细阅读后,发现是不能连接到“api.map.baidu.com”。
我打开模拟器的chrome浏览器,发现不能上网。查看手机的dns是10.0.2.3(默认的),和家里wifi不一样,所以不能上网也正常,之前居然没发现这个问题!!!
终端执行:adb shell 和 getprop,就可以查看所有的属性参数了。(window小伙伴自行百度,这个没多大差别。如果你有多个设备,记得自己选好设备。)
在里面找到这一项,就是你的dns参数。有些人是net.dns1,我的是net.eth0.dns1。这个没关系,只是等下指令 稍微改动 就行。
修改dns指令:setprop net.eth0.dns1 192.168.2.1
后面的192.168.2.1是我自己的dns,这个根据自己的情况来填写。不懂的百度下怎么查看自己的dns。
虽然提示设置失败,但是回到模拟器一看,地图已经显示出来了。
嘿嘿,在flutter设定多大的区域,地图就是多大的区域。用起来就很方便了。
过程十分痛苦,因为对flutter不是很熟悉,对Android原生更是了解很少。所以自己就像突然不能讲话,被丢到一个陌生的环境,却要我去找一个人。所以细心很重要,一定要看清楚错误提示,不要错过每一个细节和可能性。
幸好最后解决了问题,开心~
其实如果你仔细阅读过百度官方的文档,会发现里面有关于 地图的生命周期管理 。然后在这里面没有提及到,这一点虽然没提,但不可或缺,小伙伴就自行思考吧。
最后还有一点,其实我的初衷是想实现一个百度地图的plugin,但是苦于能力有限,对Android的不熟悉,最后折戟。我不得已另起项目,然后重新实现地图sdk接入。经过这次对于这些有更多更全面的认知后,有空会再次研究flutter 插件的开发,共勉,奥利给!!!
相对于iOS开发,Flutter的布局更具有灵活性,每个页面设计都不一样,相同页面可选择的布局方式也不一样,如果单纯的说应该如何去布局,我觉得不现实,大家可以参考下 Flutter官方的布局教程 。接下来,笔者,通过项目中的一个页面,来一步一步的拆解布局的流程。整个过程,基本上按照拆解、组件封装、具体布局这三步来的。
根据设计图,可以看出整体可以分成两部分,上面一部分是系统介绍模块,下面一部分是真正的登录内容,因为涉及到叠加,因此考虑用Stack;
系统介绍模块部分:整体也是涉及到叠加,考虑用Stack,分为四部分。最底部渐变色背景用一个contanier,无须指定位置,全视图扩展;载放logo图标在上一层,用Image。最后两个Text同级放在最上层。Image,Text各用Positioned包裹去指定位置。
登录内容模块是最外层是一个Contanier容器,去控制背景色和圆角。然后是一个Column元素,逐行排列。
第一行为Image,
第二行为Text,
第三行可以看成一个小Column,分两块进行布局
第四行可以看成一个小Column,分两块进行布局
第五行可以看作一个TextButton,
第六行可以看作一个Row,分三块进行布局
通过上面这样一步一步的分析后,基本上对大致的布局有了一个了解,最外层的控件大致选对(只要能实现的话,就是复杂度以及效率的问题),然后一步一步的拆解每一行的元素,如果有重复的或者觉得可以封装出来的部分,则进行下一步。
每一行的拆解,大致也是按照这个思路来进行,因此笔者在这里就不做讲解了。
在做到第三第四行的时候,发现这两个很相似,而且设计到一些交互逻辑,笔者就想对第三第四行的这种展示进行封装,觉得今后的布局可能会用到,因此在这一步,可以先把这一块儿抽离出一个控件。利用TextField来实现这种输入操作,具体的实现笔者不再详细的描述了。
经过这一步,整体的规划设计图已经有了,各个组件也都有了,接下来的工作就是组装了。
具体布局设计到一些细节的地方,例如整体Column的居中对齐(crossAxisAlignment)、间隔(Padding或Container包裹,笔者更喜欢用SizedBox占位)、居左居右居中(Align)、点击事件(GestureDetector)以及圆角(BorderRadius)等一些特殊情况。
像第六行row是放在底部的,就可以在第六行前面增加一个Spacer()去填充空白区域。
对文字颜色大小等,可以用TextStyle直接设置。
对于输入框的删除按钮,可以用Offstage这种Flutter特有的控制显示隐藏的控件。
Row:在水平方向上排列子widget的列表。
Column:在垂直方向上排列子widget的列表。
注意:这两个属于多子节点空间,可以将children排列成一行/一列,但是自身不带滚动属性,如果超出了一行,在debug下面则会显示溢出的提示。
MainAxisAlignment:主轴方向上的对齐方式,会对child的位置起作用,默认是start。
其中MainAxisAlignment枚举值:
center:将children放置在主轴的中心;
end:将children放置在主轴的末尾;
spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
start:将children放置在主轴的起点;
其中spaceAround、spaceBetween以及spaceEvenly的区别,就是对待首尾child的方式。其距离首尾的距离分别是空白区域的1/2、0、1。
MainAxisSize:在主轴方向占有空间的值,默认是max。
MainAxisSize的取值有两种:
max:根据传入的布局约束条件,最大化主轴方向的可用空间;
min:与max相反,是最小化主轴方向的可用空间;
CrossAxisAlignment:children在交叉轴方向的对齐方式,与MainAxisAlignment略有不同。
CrossAxisAlignment枚举值有如下几种:
baseline:在交叉轴方向,使得children的baseline对齐;
center:children在交叉轴上居中展示;
end:children在交叉轴上末尾展示;
start:children在交叉轴上起点处展示;
stretch:让children填满交叉轴方向;
TextDirection:阿拉伯语系的兼容设置,一般无需处理。
VerticalDirection:定义了children摆放顺序,默认是down。
VerticalDirection枚举值有两种:
down:从top到bottom进行布局;
up:从bottom到top进行布局。
top对应Row以及Column的话,就是左边和顶部,bottom的话,则是右边和底部。
TextBaseline:使用的TextBaseline的方式,有两种,前面已经介绍过。
这个是Row/Column的内的小控件,可以用来实现权重的布局
这边使用一个Container,里面是Row,使用Expanded对子节点进行权重处理,如果不使用Expanded,直接放入其他控件也是可以的,只是无法设置权重
对于内容过长的时候,会有溢出提示:
MainAxisAlignment.center:将children放置在主轴的中心;
MainAxisAlignment.start:将children放置在主轴的起点;
MainAxisAlignment.end:将children放置在主轴的末尾;
MainAxisAlignment.spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
MainAxisAlignment.spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
MainAxisAlignment.spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
下一章我们学习基础组件之Image
zone.js:
scheduleMicrotask执行流程不一定是一下流程,此处只是举例其中一种情况说明Zone的作用
假设scheduleMicrotask方法在zoneA中执行,则scheduleMicrotask方法的大致执行流程如下: