十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
相对于iOS开发,Flutter的布局更具有灵活性,每个页面设计都不一样,相同页面可选择的布局方式也不一样,如果单纯的说应该如何去布局,我觉得不现实,大家可以参考下 Flutter官方的布局教程 。接下来,笔者,通过项目中的一个页面,来一步一步的拆解布局的流程。整个过程,基本上按照拆解、组件封装、具体布局这三步来的。
创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于网站设计制作、网站建设、台山网络推广、小程序开发、台山网络营销、台山企业策划、台山品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联公司为所有大学生创业者提供台山建站搭建服务,24小时服务热线:028-86922220,官方网址:www.cdcxhl.com
根据设计图,可以看出整体可以分成两部分,上面一部分是系统介绍模块,下面一部分是真正的登录内容,因为涉及到叠加,因此考虑用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特有的控制显示隐藏的控件。
Flutter中自定义组件一般有两种方式:
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。
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
效果如下
对于一些复杂或不规则的UI,我们可能无法使用现有的 Widget 组合去实现,比如需要一个带动画的进度条,
又或者是一个特殊形状的多边形等等,当然有时候我们可以直接用图片去实现,但是并没有达到我们想要
的效果,反而会让我们产生不良的体验。
几乎所有的UI系统都会提供一个自绘UI的接口,这个接口通常会提供一块2D画布Canvas,Canvas内部封装了
一些基本绘制的API,开发者可以通过Canvas绘制各种自定义图形。在Flutter中,提供了一个CustomPaint Widget,
它可以结合一个画笔CustomPainter来实现绘制自定义图形。
我们看看 CustomPaint 构造函数:
1.painter: 背景画笔,会显示在子节点后面;
2.foregroundPainter: 前景画笔,会显示在子节点前面
3.size:当child为null时,代表默认绘制区域大小,如果有child则忽略此参数,画布尺寸则为child尺寸。如果有child但是想指定画布为特定大小,可以使用SizeBox包裹CustomPaint实现。
4.isComplex:是否复杂的绘制,如果是,Flutter会应用一些缓存策略来减少重复渲染的开销。
5.willChange:和isComplex配合使用,当启用缓存时,该属性代表在下一帧中绘制是否会改变。
可以看到,绘制时我们需要提供前景或者背景画笔,两者也可以同时提供,
我们的画笔需要继承 CustomPainter 类,我们在画笔类中实现真正的绘制逻辑。
顾名思义画布的意思,我们绘制布局当然是在一张画布上进行绘制,画布为我们绘制图形提供了很多方法。(熟悉画布的就无需再看了)
在绘制之前我们需要准备画笔 Paint,就如画画一样,你用什么笔就能画什么样的画,在Paint中,
我们可以配置画笔的各种属性如粗细、颜色、样式等。如:
好了,继承CustomPainter类,然后准备好画笔,就可以在画布上尽情的挥洒了!
写的挺简单的,就是介绍了一下自定义view的准备工作以及画布画笔的功能,具体实战请看下一篇博客。