Flutter之构建布局
你会学到什么
· Flutter的布局机制是如何工作的。
· 如何垂直和水平布置小部件。
· 如何创建Flutter布局。
本篇博客介绍绘制下面的布局:
step0: 创建应用程序基本代码
确保您的Flutter环境已经安装完成,然后执行以下操作:
- 创建一个新的Flutter应用程序。
- 将其中的内容替换
lib/main.dart
为以下代码:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter layout demo'),
),
body: const Center(
child: Text('Hello World'),
),
),
);
}
}
step1: 绘制布局图
第一步是将布局分解为基本元素:
- 识别行和列
- 布局是否包含网格?
- 是否有重叠元素?
- UI是否需要选项卡?
- 注意需要哦对齐、填充或边框的区域
首先,确定较大的元素。在此示例中,四个元素排列成一列:一个图像、两行和一个文本块。
接下来,绘制每一行。第一行称为标题部分,有3个子项:一列文本、一个星形图标和数字。它的第一个孩子,列,包含2行文本。第一列占用大量空间,因此必须将其包装在Expanded小部件中。
第二行,称为Button部分,也有3个子项:每个子项都是一个包含图标和文本的列。
绘制布局图后,最容易采用自下而上的方法来实施它。为了尽量减少深层嵌套布局代码的视觉混乱,将一些实现放在变量和函数中。
step2: 实现标题行
首先,您将在标题部分构建左栏。在MyApp
类的build()
方法顶部添加以下代码:
lib/main.dart
Widget titleSection = Container(
padding: const EdgeInsets.all(32),
child: Row(
children: [
Expanded(
/*1*/
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(bottom: 8),
child: const Text(
'Oeshinen Lake Campground',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Text(
'Kandersteg, Switzerland',
style: TextStyle(
color: Colors.grey[500],
),
),
],
),
),
/*3*/
Icon(
Icons.star,
color: Colors.red[500],
),
const Text('41'),
],
),
);
/*1*/
将Column放在Expanded小部件中会拉伸该列以使用该行中所有剩余的可用空间。将crossAxisAlignment
属性设置为CrossAxisAlignment.start
将列定位在行的开头
/*2*/
将第一行文本放在Container
中可以添加填充。Column
中的第二个子项,也是文本,显示为灰色 。
/*3*/
标题行中的最后两项是星形图标,设置为红色,以及文本“41”。正好都在容器中,并沿每条边填充32像素。将标题部分添加到应用程序正文中,如下所示:
step3: 实现按钮行
按钮部分包含3列,它们使用相同的布局——行文本上方的一个图标。该行中的列间距均匀,文本和标题使用原色绘制。
由于构建每一列的代码几乎相同,因此创建一个名为buildButtonColumn()
的私有辅助方法 ,它采用一种颜色、一个图标和文本,并返回一个列,其小部件以给定颜色绘制。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@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,
),
),
),
],
);
}
}
该函数将图标直接添加到列中。文本位于Container内,只有顶部间距,将文本与图标分开。
通过调用函数并传递特定位于该列的颜色、图标和文本来构建包含这些列的行。使用MainAxisAlignment.spaceEvenly
沿主轴对齐列,以在每列之前、之间和之后均匀地排列可用空间。在build()
方法中的titleSection
声明下方添加以下代码:
lib/main.dart (buttonSection)
Color color = Theme.of(context).primaryColor;
Widget buttonSection = Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildButtonColumn(color, Icons.all, 'CALL'),
_buildButtonColumn(color, Icons.near_me, 'ROUTE'),
_buildButtonColumn(color, Icons.share, 'SHARE'),
],
);
将按钮部分添加到body:
step4: 实现文本部分
将文本部分定义为变量。将文本放入Container
并沿每条边添加填充。在buttonSection
声明下方添加以下代码:
lib/main.dart (textSection)
Widget textSection = const Padding(
padding: 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,文本行将在单词边界换行之前填充列宽。
将文本部分添加到body:
step5: 实现图像部分
四个列元素中的三个现已完成,只留下图像。将图像文件添加到示例中:
- 在项目顶部创建一个
asset
目录。 - 添加 lake.jpg
- 更新
pubspec.yaml
文件以包含asset
标签。这使图像可用于您的代码。
现在您可以从代码中引用图像:
BoxFit.cover
告诉框架图像应该尽可能小但覆盖它的整个渲染框。
step6: 最后重构一下
在这最后一步中,将所有元素排列在ListView
中,而不是Column
中,因为当应用程序在小型设备上运行时,ListView
支持应用程序主题滚动。
Dart code:
main.dart
Image: images
Pubspec: pubspec.yaml
就是这样!当您hot reload夹在应用程序时,您应该会看到与顶部截图相同的应用程序布局。
转载自:https://juejin.cn/post/7192593306109526074