未子涵 2019-06-26
不知不觉已经到了第7篇,然而很多萌新玩家可能还是不知道如何堆砌控件,像用CSS一样搭出漂亮的APP界面,我也一样,红红火火恍恍惚惚,直到今天含泪读完Flutter布局基础,仿佛打开了一个全新的世界。
在flutter中,一切皆控件!一切皆控件!一切皆控件!牢牢记住这个概念。Text是控件,Image是控件,Icon是控件,布局脚手架也Scaffold也是控件,甚至整个APP也是控件。
用户自定义控件分为有状态控件和无状态控件两种类型,其特性在前面的笔记4中可以感受感受。
flutter的内置控件分为两种:
child
或children
。child
可承载单个子控件,children
可承载多个子控件。每个布局控件有默认的布局方式,使其子控件按照自己的样式安放到位子上。布局控件提供了各种样式的参数,可实现子控件的对齐(align)、缩放(size)、包装(pack)和嵌套(Nest)。简单总结为:布局控件是为了实现可视控件的各种视觉效果而做的包装,比如前端的html为了实现sticky、双飞翼、圣杯等布局常常内容区外层添加div包裹层。布局控件也是可以模拟显示的,通常用于调试布局样式时用到的网格线、标尺、动画帧等。启用方式:
1.在main.dart中,引入包:
import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
2.在main
函数中打开开关:
void main() { debugPaintSizeEnabled = true; //打开视觉调试开关 runApp(new MyApp()); }
运行代码后APP效果如下:
flutter的内置控件已经定义了很多属性,玩家可以参考Widgets Catalog了解每种控件的详细属性和用法。本篇通过几个例子,介绍页面上的控件如何堆砌和布局。
别着急,由于下面的案例中,可能用到图片,先交待一下加载图片的基本配置方法:
flutter: uses-material-design: true assets: //如果没有这个属性则添加到flutter标签下 - images/lake.jpg //声明图片的路径
new Image.asset( 'images/lake.jpg', //图片的路径 width: 600.0, //图片控件的宽度 height: 240.0, //图片控件的高度 fit: BoxFit.cover, //告诉引用图片的控件,图像应尽可能小,但覆盖整个控件。 ),
行(Row)和列(Column),是flutter中最常用的两个布局控件,他们只能容纳当前屏幕尺寸大小的内容,如果其内部的子控件超出屏幕尺寸,不但不会自动生成滚动条,还会报错。
案例1-行排列
如图上图所示,图中有3个100px宽的图片,通过水平平均间隔的方式居中横向排列显示到一行中,代码示例:
new Center( //居中控件 child: new Row( //行控件 mainAxisAlignment: MainAxisAlignment.spaceEvenly, //对齐方式:平均间隔 children: [ new Image.asset('images/pic1.jpg'), //引入三张图片 new Image.asset('images/pic2.jpg'), new Image.asset('images/pic3.jpg'), ] ) )
可以看到上图用到了2个布局控件Center和Row,通过Center包裹Row,使行控件保持居中,而ROW控件包裹了3个图片控件Image,通过配置Row的mainAxisAlignment对齐属性,使三个图片空间通过平均间隔的方式进行横向排列。
完整代码:
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
案例2-列排列
如上图所示,还是那3张图,通过纵向平均间隔的方式显示到一列中,代码如下:
new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, //对齐方式:平均间隔 children: [ new Image.asset('images/pic1.jpg'), new Image.asset('images/pic2.jpg'), new Image.asset('images/pic3.jpg'), ] ) )
完整代码:
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
对比案例1和2可以看到,代码结构相同,Row和Column中都用到了mainAxisAlignment属性,除此以外还有crossAxisAlignment属性。值得注意的是,在Row中mainAxisAlignment控制水平方向对齐,crossAxisAlignment控制垂直方向对齐,而在Column中则正好相反。相关参数值请参考MainAxisAlignment和CrossAxisAlignment
案例3-行列嵌套
如上图,我们将图中的元素按图中的框线进行分解:
1.最外层的使用Row控件包裹,使其内部的两个子控件:浅蓝色框的菜品介绍和右边的菜品大图横向排列,代码如下:
new Scaffold( //脚手架控件 appBar: new AppBar( //工具栏控件 title: new Text(widget.title), ), body: new Center( child: new Container( //Container控件用于调整外边距 margin: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0), height: 600.0, child: new Card( //Card控件控制卡片的视觉效果 child: new Row( //Row控件使其子控件横向排列 crossAxisAlignment: CrossAxisAlignment.start, //纵向对齐方式:起始边对齐 children: [ new Container( //Container控件用于调整宽度 width: 440.0, child: leftColumn, //左边的菜品介绍控件 ), mainImage, //右边的大图控件 ], ), ), ), ) )
2.把浅蓝色框内的信息,用Column包裹,使其内容垂直排列:
new Container( padding: new EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0), child: new Column( //Column控件,使其子控件垂直排列 children: [ titleText, //标题行,包含了可视Text控件 subTitle, //副标题行,包含了可视Text控件 ratings, //投票信息行 iconList, //小图标行 ], ), );
3.由于titleText和subTitle都是简单的包装了Text控件,不再贴代码和注释,重点讲下ratings和iconList:
ratings和iconList控件是垂直排列的两行,而各自内部有自己的布局信息,因此将这两行分别拆解为:
ratings下包含了两个水平排列:Row控件用于显示星级,Text控件用于显示用户浏览数,而评分星级控件ROW又分解为5个水平排列的Icon控件。
iconList横向排列了3个纵向显示的控件,层次一目了然。
对照代码结构:
//ratings控件 new Container( padding: new EdgeInsets.all(20.0), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ new Row( mainAxisSize: MainAxisSize.min, //mainAxisSize,可压缩或伸长行内控件的间距 children: [ new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), new Icon(Icons.star, color: Colors.black), ], ), new Text( '170 Reviews', style: new TextStyle( color: Colors.black, fontWeight: FontWeight.w800, fontFamily: 'Roboto', letterSpacing: 0.5, fontSize: 20.0, ), ), ], ), ) //iconList控件 new Container( padding: new EdgeInsets.all(20.0), child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ new Column( children: [ new Icon(Icons.kitchen, color: Colors.green[500]), new Text('PREP:'), new Text('25 min'), ], ), new Column( children: [ new Icon(Icons.timer, color: Colors.green[500]), new Text('COOK:'), new Text('1 hr'), ], ), new Column( children: [ new Icon(Icons.restaurant, color: Colors.green[500]), new Text('FEEDS:'), new Text('4-6'), ], ), ], ), )
Row和Column可以相互包裹,使页面能够实现整齐的布局,只因其特性总是横向或纵向充满父控件,比如最外层使用时,会自动充满全屏幕。但是当页面内容需要超出屏幕尺寸时,就用ListTile和ListView代替。
完整代码(由于手机屏幕尺寸无法适应此案例,运行后长和宽都会报溢出错误,大家最好使用平板虚拟机测试此案例,或者调整代码中的字体大小和控件尺寸,以满足显示要求):
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
案例4-缩放
上图中,三个横向排列的图片控件,中间控件的尺寸比两边的大一倍,代码如下:
new Center( child: new Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ new Expanded( child: new Image.asset('images/pic1.jpg'), ), new Expanded( //使用Expanded控件对Image控件进行包裹 flex: 2, //flex值默认为1,这里改成2之后,其子控件2倍放大 child: new Image.asset('images/pic2.jpg'), ), new Expanded( child: new Image.asset('images/pic3.jpg'), ), ))
完整代码:
Dart code: main.dart
Images: images
Pubspec: pubspec.yaml
由于处理逻辑和布局样式都一起书写到代码中,加上控件的嵌套,flutter的代码会如同html的标签一样嵌套很多层,对前端开发者可能需要时间适应,但对我这种新萌来说降低了从CSS和处理代码之间来回对照的麻烦,并且flutter的内置控件默认的样式已经十分整洁,无需单独再学习类似前端CSS处理页面布局的语法和结构,总体来说降低了不少学习成本,上手更快更简单。能在短时间内掌握生产技能,成就感油然而生,自然有继续学下去的动力。
以上便是最基础的排列布局介绍,相信看到这里的小伙伴已经明白怎么写APP了,今天就到这里~感谢大家支持!
flutter 中文社区(官方QQ群:338252156)