文学起点网
当前位置: 首页 文学百科

ui布局详细讲解(一个月带你入门Flutter)

时间:2023-05-31 作者: 小编 阅读量: 2 栏目名: 文学百科

Flutter系列的文章我会持续更新一个月左右,力求利用1个月带大家入门Flutter,抓住这波技术风口,欢迎大家关注。是否存在Widget之间的覆盖?运行起来的效果如下图所示:第3步:实现按钮行按钮行有3个列,每个列都是同样的布局组成:1个Icon、1个Text。

Flutter系列的文章我会持续更新一个月左右,力求利用1个月带大家入门Flutter,抓住这波技术风口,欢迎大家关注。同时如果觉得这里代码排版不是很舒服的读者可以关注我的微信公众号“IT工匠”,我会同步更新,另外微信公众号上还有很多互联网必备资源(涉及算法、数据结构、java、深度学习、计算机网络、python、Android等互联网技术资料),欢迎大家关注、交流。

摘要

本文通过一个简单的实例来逐步为大家介绍如何在Flutter中构建漂亮的布局,通过本文你将会了解到以下几点:

  • Flutter的布局机制是如何工作的
  • 如何在垂直方向和水平方向布局Widget
  • 如何在Flutter中进行Widget的布局

本文档主要介绍如何在Flutter中进行布局,你将最终会构建一个下图这样的页面:

本文将一步一步带你构建一个像上图那样的页面。

第0步:创建一个Flutter项目
  1. 创建一个Flutter项目
  2. 将该项目的app bar的标题和app的标题设置为下面这样:

Widget build(BuildContext context) {return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Center( child: Text('Hello World'), ), )); }

设置完成后运行起来效果如下图所示:

第1步:分析页面的布局逻辑

第一步是将整个页面布局分解为基本元素,主要从以下几点入手

  • 辨识行(Row)和列(Column)
  • 布局中是否存在网格(grid)?
  • 是否存在Widget之间的覆盖?
  • 整个UI布局是否需要tab栏?
  • 关注需要对其(alignment)、填充(padding)、边框(border)的区域

那么我们先来看一下整个页面的主要组成部分:

可以看到,整个页面的主要组成部分就是由红色框标注出来的4部分,这4部分位于同一个列(Column),分别是:1个Image、2个Row、1个Text。

再深入地分析一下每一个行(Row):

  • 第1行,也就是标题栏(Title section),它有3列:1个由2行text组成的列(Column)、1个星星的Icon、1个数字:

可以看到,由于第1个列(Column)占据了整个行的大部分空间,所以其应该被Expanded Widget包裹。

  • 第二行,我们也就是按钮列(button section),同样也包含了3个子元素,每一个子元素都是1个行,行里面的内容是1个icon和1个text:
  • 第三行:第三行没有很复杂的构成,就是单纯的text块。

经过以上的分析,我们将一个复杂的页面分解为了多个简单的组成部分,这样可以简化整个页面的实现,为了避免布局代码的混乱,我们应该利用变量和函数来构建布局的子部分,这一点我会在下面的代码中进行演示。

第2步:实现第一行(title Row)

直接给出代码,具体的解释在代码的注释中,大家注意看注释:

Widget titleSection = Container( //为整个Widget(即这一行)的所有所有方向设置32px的填充 padding: const EdgeInsets.all(32), child: Row( children: [ Expanded( /** 将Column放置在Expanded中,由于Expanded会默认占据所有当前Row的空闲可用空间,所以这个Column也会自然被拉伸的占据完所有当前Row可用的空闲空间。 */ child: Column( /**将Column的crossAxisAlignment属性设置为CrossAxisAlignment.start以保证这个列中的元素(即children属性中的Widget)在水平方向上排列在当前Column的起始位置 */ crossAxisAlignment: CrossAxisAlignment.start, children: [ /** 将这个Text放在Container中的目的是通过Container来添加填充(padding) */ Container( padding: const EdgeInsets.only(bottom: 8), child: Text( 'Oeschinen Lake Campground', style: TextStyle( fontWeight: FontWeight.bold, ), ), ), Text( 'Kandersteg, Switzerland', style: TextStyle( color: Colors.grey[500], ), ), ], ), ), /** 最后的2个元素分别是1个Icon和1个Text,分别用来显示星星和数字 */ Icon( Icons.star, color: Colors.red[500], ), Text('41'), ], ),);

直接将上面的变量titleSection放在在app body中即可:

@override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter layout demo', debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Column( children: <Widget>[titleSection], ))); }

注意,这里通过使用变量titleSection来达到简化布局代码的目的,这样就不会导致MaterialApp(..)中的代码太长、太混乱。

运行起来的效果如下图所示:

第3步:实现按钮行(button row)

按钮行(button section)有3个列,每个列都是同样的布局组成:1个Icon、1个Text。这一行中的列之间的间距都是均匀的,由于构建每一列的代码几乎相同,因此创建一个名为buildbuttoncolumn()的私有方法,该方法接收一个颜色(Color)参数、一个图标(Icon)参数和1个文本(Text)参数,并返回一个具有以给定颜色绘制的Widget的列(Column),代码如下:

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // ··· } Column _buildButtonColumn(Color color, IconData icon, String label) { return Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, color: color), Container( margin: const EdgeInsets.only(top: 8), child: Text( label, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: color, ), ), ), ], ); }}

_buildButtonColumn()方法将Icon直接添加到Column中,而Text是先用Container进行包裹,然后再将Container添加到Column中,这样做的目的是借助Container为Text设置顶部填充(padding),这样就不至于Text和Icon距离过近。

完成了_buildButtonColumn()函数之后,我们只需要在需要构建列(Column)的时候调用该函数并传入对应的3个参数即可构建出我们需要的列:

Color color = Theme.of(context).primaryColor;Widget buttonSection = Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildButtonColumn(color, Icons.call, 'CALL'), _buildButtonColumn(color, Icons.near_me, 'ROUTE'), _buildButtonColumn(color, Icons.share, 'SHARE'), ], ),);

注意这里设置Row的mainAxisAlignment属性值为MainAxisAlignment.spaceEvenly,目的是让Row中的列均匀地占满整个行的可用空间。

然后将变量buttonSection放在app body中:

return MaterialApp( title: 'Flutter layout demo', debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Column( children: <Widget>[titleSection, buttonSection], )));

运行效果图如下图所示:

第4步:实现Text 部分

将Text部分定义为一个变量,然后将Text放置在一个Container中,并为Container设置padding属性:

Widget textSection = Container( padding: const EdgeInsets.all(32), child: Text( 'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese ' 'Alps. Situated 1,578 meters above sea level, it is one of the ' 'larger Alpine Lakes. A gondola ride from Kandersteg, followed by a ' 'half-hour walk through pastures and pine forest, leads you to the ' 'lake, which warms to 20 degrees Celsius in the summer. Activities ' 'enjoyed here include rowing, and riding the summer toboggan run.', softWrap: true, ),);

注意这里设置softwrap属性值为true,这样可以保证文字可以在单词分界的地方换行而不是在单词中间换行。

然后将上面的textSection变量放在app body中:

return MaterialApp( title: 'Flutter layout demo', debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Column( children: <Widget>[titleSection, buttonSection, textSection], )));

运行效果图如下图所示:

第5步:实现Image部分

到现在为止我们已经完成了4行中的3行,只剩下图像那行还没实现,这一步我们来实现图像的显示:

  • 在项目的顶级目录下创建一个images文件夹
  • 将下图放在刚才创建的images文件夹下,命名为lake.jpg
  • 更新pubspec.yaml文件,添加assets标签,配置图片路径,这样就可以在代码中访问到你存放的图片:

flutter:uses-material-design: trueassets:- images/lake.jpg

然后我们就可以在代码中引用该图了:

return MaterialApp( title: 'Flutter layout demo', debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Column( children: <Widget>[ Image.asset( 'images/lake.jpg', width: 600, height: 240, fit: BoxFit.cover, ), titleSection, buttonSection, textSection ], )));

运行起来效果如下:

第6步:另一种尝试

我们来看前几步完成之后的最终代码:

return MaterialApp( title: 'Flutter layout demo', debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Column( children: <Widget>[ Image.asset( 'images/lake.jpg', width: 600, height: 240, fit: BoxFit.cover, ), titleSection, buttonSection, textSection ], )));

注意,我们将body的属性值设置为了Column,然后在Column中放置了我们实现的几个子Widget,现在我们换种方式,使用ListView来取代这个Column:

return MaterialApp( title: 'Flutter layout demo', debugShowCheckedModeBanner: false, home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: ListView( children: [ Image.asset( 'images/lake.jpg', width: 600, height: 240, fit: BoxFit.cover, ), titleSection, buttonSection, textSection ], )));

效果如下:

可以看到,使用Column和使用ListView的静态视觉效果是一样的,那我们到底应该使用Column还是ListView呢?二者的区别在哪里呢?答案就在”动态”,二者在动态下的效果是不一样的,再具体点,使用Column构建的Widget是不支持滚动的,即不支持进行上下或者左右的滚动事件,而使用ListView会支持滚动事件,就像下面这样:

以上就是本文的所有内容,希望大家通过本文可以对Flutter的布局有更深入的了解和认知,我们下篇文章再见~
    推荐阅读
  • 荷塘月色简笔画彩图(荷塘的场景图简笔画)

    今日份简笔画荷塘月色.感恩日记1.,我来为整理几张简单漂亮的荷塘月色简笔画彩图?以下简笔画图片总有一款是你喜欢的,希望对你有帮助来看看吧!荷塘月色简笔画彩图今日份简笔画荷塘月色.感恩日记1.荷塘月色好看的儿童画图片儿童简笔画大全荷塘月色简笔画儿童画

  • 直硬头发软化前后效果图(头发软化前后效果图)

    可以使头发变软,变柔顺,变贴服,且价格也很便宜,普通的美发沙龙价格为50到80元左右,软化比较自然。头发软化后几天可以洗刚做完软化2至3天不要洗头,刚做完软化不要用力拉头发,会有损发质和效果。软化也是伤头发的,不过比不停地做一次性夹头发而言小很多,如果是短发做软化还是不错的。如果想让头发蓬蓬的,最好不要全头做软化,甚至不建议做软化。具体情况,建议咨询理发师。用药水要用好一点的,对头发伤害才不会很大。

  • 赞美运动员的话(赞美运动员的话有什么)

    年轻的我们自信飞扬,青春的气息如同出生的朝阳,蓬勃的力量如同阳光的挥洒此时此刻,跑道便是我们精彩的舞台,声声加油便是我们最高的奖项论何成功,谈何荣辱,心中的信念只有一个:拼搏,我来为大家科普一下关于赞美运动员的话?赞美运动员的话年轻的我们自信飞扬,青春的气息如同出生的朝阳,蓬勃的力量如同阳光的挥洒。所有的努力都是为了迎接这一刹那,所有的拼搏都是为了这一声令下。

  • 长安uni-k车主反映这款车怎么样(新车长安UNI-K登场)

    据长安汽车最新消息,中大型SUVUNI-K官图曝光,这是长安UNI系列的第二款车型。新车将搭载蓝鲸系列2.0T发动机并匹配8AT变速箱,将于广州车展首发亮相。新车亮点1.采用了全新的“V”型面设计和无边界格栅。新车概况新车前脸依然采用无边界设计并融入了V型面概念,不同于UNI-T,UNI-K的大灯位置设计在了最上方。车尾方面采用了时下流行的贯穿式尾灯设计,与UNI-T的V型后导流造型不同,UNI-K采用了新的航天器式造型,立式尾灯十分显眼。

  • 渡劫经典语录(关于渡劫的语录精选)

    情到深处人孤独,爱至穷时尽沧桑堕落的天使啊,你无知的游走着。我将于茫茫人海中访我唯一灵魂之伴侣;得之,我幸;不得,我命。玲珑骰子安红豆,入骨相思君知否。于千万人之中遇见你所遇见的人,于千万年时间无涯的荒野里,没有早一步,也没有晚一步,刚巧赶上了。生命是一朵千瓣莲花,我拒绝了绽放的同时,我也拒绝了枯萎和零落。就算哭泣也要皱眉优雅,就算失败也要转身潇洒。之后我也学会了阳奉阴违,发生了什么与我再无所谓。

  • 孤城闭什么时候上映(谁是主演)

    以下内容大家不妨参考一二希望能帮到您!孤城闭什么时候上映《孤城闭》将于2020年起在湖南卫视上映播出。该剧主要由王凯、江疏影、任敏、杨玏、边程、叶祖新、喻恩泰、王楚然、刘钧、孙坚等主演。《孤城闭》改编自米兰lady同名小说,以北宋为背景,在风起云涌的朝堂之事与剪不断理还乱的儿女情长之间,还原了一个复杂而真实的宋仁宗。

  • 大众朗逸所有灯图解(认识汽车灯图解)

    大众朗逸所有灯图解作为新手,汽车灯光就是一道难题,下面我们一起通过图解来认识一下汽车各种灯光吧。双闪灯的作用是当车辆发生意外情况后,引起其他车辆警惕,防止发生追尾事故。当踩下制动踏板后,制动灯立即亮起,并发出红色灯光,提醒后方车辆。倒车灯是白色,作用是为了照亮车尾的路面,减少倒车时盲区,另外也是对后方的提醒。

  • 雪里红的腌制方法(做雪里红腌菜的步骤)

    下面更多详细答案一起来看看吧!雪里红的腌制方法雪里红摘干净,根部用刀劈开,正一层反一层放入盆中,取盐均匀地洒在雪里红上,腌制1-2天。烧开水放凉,加盐,搅拌均匀,盐水倒入雪里红中泡制一天。泡好的雪里红捆成一小捆放入密封罐,倒入泡雪里红的盐水,盖好密封罐,即吃即取。

  • 郑州婚纱照推荐哪家好(郑州拍婚纱照团购)

    中国红喜嫁秀爆朋友圈的婚纱照中式婚纱照新中式婚纱照婚纱照风格高级感婚纱照婚纱照秀禾服的中式嫁衣,是完美诠释了东方女性温婉古典美。让人完全移不开目光~每一个女孩子都应该拥有这样华丽的喜嫁风太精致完全属于中式婚纱照的浪漫感~

  • 胎梦最准的位置(从胎梦看看你腹中的孩子给你暗示了吗)

    估计生完孩子和正在孕期的妈妈都会经历过这种事情,就是我们会经常做梦,而且会梦见一些动物植物什么的,这在老人眼里属于“胎梦”。你梦见的什么会预示着即将出生的宝宝是男孩还是女孩。你的胎梦准不准,来看看一下别人的胎梦。哈哈,看来有些胎梦还是挺准的,或许都是巧合吧,总之,宝宝来了就是我们的命中注定。