小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
从上一篇中主要了解了Flutter
环境的搭建,以及ListView
的简单使用,这篇中将继续熟悉一下其他的一些Widget
。
工程创建
首先创建一个工程,这里可以通过Android Studio
或者命令行创建,进入到工程的目录路径,命令行如下:
# -i:iOS
# objc:选择Objective-C语言,这里不选择语言,iOS默认是Swift,Android默认的是Kotlin
flutter create -i objc flutter_demo
创建工程以后会在lib/main.dart
默认生成一些简单的UI样式,运行看一下效果(这里打开的是iPhone
的模拟器)。
从运行结果可以看到文字和按钮的显示,点击按钮计数会增加。下面我们删掉原来的代码,然后自定义一些
Widget
玩玩,看看效果,为了使代码不要太乱,下面一个Widget
创建一个dart
文件分开。
常用Widget
在lib
文件目录下再创建一个views
目录。删掉之前的代码,下面是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(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
body: Container(),
),
);
}
}
Text
创建一个StatelessWidget
的text_widget.dart
文件放在views
里,首先看一下Text
的一些属性。
const Text(
String this.data, {
Key? key,
this.style,
this.strutStyle,
this.textAlign,
this.textDirection,
this.locale,
this.softWrap,
this.overflow,
this.textScaleFactor,
this.maxLines,
this.semanticsLabel,
this.textWidthBasis,
this.textHeightBehavior,
})
可以对Text
设置样式,对齐方式,文字方向,最大行数等等。可以简单的设置一些属性
import 'package:flutter/material.dart';
class TextWidget extends StatelessWidget {
const TextWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Text(
'Flutter 是 Google 发布的一个用于创建跨平台、高性能移动应用的框架。Flutter 和 Qt mobile 一样,都没有使用原生控件,相反都实现了一个自绘引擎,使用自身的布局、绘制系统。',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16.0,
color: Colors.red,
),
);
}
}
把main.dart
的Container
替换刚创建的TextWidget
,再运行。
如果要设置最大行数,然后多余的用
...
的方式,可以设置maxLine
和overflow
属性。完成后点击Hot reload
就可以看到效果了。
RichText
在文本样式里经常会用到富文本,Flutter
中提供了富文本的Widget
就是RichText
,看看RichText
的属性定义
RichText({
Key? key,
required this.text,
this.textAlign = TextAlign.start,
this.textDirection,
this.softWrap = true,
this.overflow = TextOverflow.clip,
this.textScaleFactor = 1.0,
this.maxLines,
this.locale,
this.strutStyle,
this.textWidthBasis = TextWidthBasis.parent,
this.textHeightBehavior,
})
要求传的text
这里传TextSpan
,TextSpan
和Text
的区别是有children
属性,所以可以做嵌套,这样就是可以对文本设置不同的样式。
const TextSpan({
this.text,
this.children,
TextStyle? style,
this.recognizer,
MouseCursor? mouseCursor,
this.onEnter,
this.onExit,
this.semanticsLabel,
this.locale,
this.spellOut,
})
把之前的代码用RichText
里嵌套TextSpan
稍改一下,然后运行,就实现了简单的富文本效果。
Container
再创建一个container_demo.dart
文件,返回一个Container
的Widget
,然后引入到main
的body
里,我们给Container
设置个颜色,运行。
可以看到整个
body
被Container
占满,它是个弹性布局,我们在Container
里面放个Row
,然后再嵌套个Icon
,代码如下:
import 'package:flutter/material.dart';
class ContainerDemo extends StatelessWidget {
const ContainerDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
child: Row(
children: [
Container(
color: Colors.red,
child: const Icon(Icons.add),
),
],
),
);
}
}
再次运行。
可以看到之前黄色占满
body
的Container
变小了,所以如果Container
不设置宽度和高度会受到子部件的大小影响。接着看一下Container
的属性:
Container({
Key? key,
this.alignment,
this.padding,
this.color,
this.decoration,
this.foregroundDecoration,
double? width,
double? height,
BoxConstraints? constraints,
this.margin,
this.transform,
this.transformAlignment,
this.child,
this.clipBehavior = Clip.none,
})
margin & padding
在上面的代码中再设置一下padding
和margin
,看一下效果,代码如下:
红色
Container
到加号图标的距离是30,也就是内边距padding
属性,红色Container
到黄色的距离是20,也就是外边距margin
属性。
alignment
上面的Container
内嵌套了Row
,Row
是横向占满屏幕的,现在删除之前的Row
,在Container
内放一个Text
,然后设置它的alignment
(值的范围是从-1~1),再次运行看一下效果。
通过
alignment
可以设置元素的坐标点。
Row
Row
是一个横向布局的Widget
,横向会占满屏幕,纵向会根据子部件的大小弹性布局,接下来再创建一个row_demo.dart
,在Row
里放置3个Icon
,也设置alignment
为(0, 0),代码如下:
import 'package:flutter/material.dart';
class RowDemo extends StatelessWidget {
const RowDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
alignment: const Alignment(0, 0),
color: Colors.yellow,
child: Row(
children: [
Container(
child: const Icon(Icons.add, size: 45,),
color: Colors.red,
),
Container(
child: const Icon(Icons.ac_unit, size: 45,),
color: Colors.blue,
),
Container(
child: const Icon(Icons.access_alarm, size: 45,),
color: Colors.white,
),
],
),
);
}
}
接下来运行看一下效果
可以看到图标在横向是靠左边的,纵向是中心位置,因为
Row
是占满横向的,所以对于Row
来说alignment
设置x
轴方向是无效的,同样对于Column
设置y
轴方向是无效的。
Column
Column
是一个纵向布局的Widget
,纵向占满屏幕,横向会根据子部件大小自动布局,把上面的代码的Row
改成Column
,运行。
Stack
Stack
是一个层叠布局的Widget
,从内层忘外层布局,如果各个子部件的大小一致,外层Widget
会覆盖内层的Widget
,还是上面的代码,只是改成Stack
,运行。
可以看到只显示最后面添加的
alarm
的Icon
图标,我们把每个子Widget
的大小,这样就更直观一点。
更改大小后,可以看到
Stack
的子部件是堆叠显示的。
主轴和交叉轴
Row
、Column
和Stack
都有主轴
和交叉轴
的概念,也就是mainAxisAlignment
和crossAxisAlignment
属性,横向布局主轴方向是往右的,纵向布局主轴方向是往下的,层叠布局主轴方向是往外的,交叉轴是主轴的垂直方向。
mainAxisAlignment
先看一下MainAxisAlignment
的定义。
enum MainAxisAlignment {
start,
end,
center,
spaceBetween,
spaceAround,
spaceEvenly,
}
前三个很好理解,start
是默认的从开始方向,end
是从结束方向开始,center
是中间位置。我们以Row
作为例子,分别在这3种方式运行看看效果。
下面再看一下
spaceBetween
、spaceAround
、spaceEvenly
的效果都是什么样的?
根据运行效果可以看到:
spaceBetween
: 剩下的空间平均分布到小部件之间。spaceAround
: 剩下的空间平均分布到小部件周围。spaceEvenly
: 剩下的空间和小部件一起平均分。
crossAxisAlignment
看一下CrossAxisAlignment
的定义。
enum CrossAxisAlignment {
start,
end,
stretch,
baseline,
}
直接加上crossAxisAlignment
相关属性运行看一下效果。
前3个属性运行都正常,但改为
baseline
运行报错了,这里baseline
属性要配合Row
组件的textBaseline
属性使用,代码如下:
Widget build(BuildContext context) {
return Container(
alignment: const Alignment(0, 0),
color: Colors.yellow,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Container(
child: const Icon(Icons.add, size: 120,),
color: Colors.red,
),
Container(
child: const Icon(Icons.ac_unit, size: 60,),
color: Colors.blue,
),
Container(
child: const Icon(Icons.access_alarm, size: 30,),
color: Colors.white,
),
],
),
);
}
再次运行,可以看到和end
效果一样。
这时我们把
Icon
改成Text
,并把文字大小设置成不一样,再看效果。
可以看到所有文字的底部的对齐的。
start
: 开始位置对齐。end
: 结束位置对齐。stretch
: 交叉轴方向占满屏幕。baseline
: 需要配合textBaseline
使用,文字底部对齐。
Expanded
接下来把之前Row
的children
内的子部件再嵌套在Expanded
里,看一下效果。
子控件占满主轴方向,如果主轴方向放不下会自动换行。
Expanded
: 在主轴方向不会剩下间隙,将被Expanded拉伸。
总结
通过这篇对Flutter
常用的Widget
做了了解,也在实际运行后看不同Widget
对应属性的使用的改变,根据这些Widget
的使用做个简单的总结。
Text
控件的使用,以及RichText
富文本控件的使用。Container
的用法,Alignment
的参数x
和y
。Row
和Column
,认识了主轴和交叉轴的概念。Stack
的用法,层叠显示。Expanded
,填充Widget,可以占满父组件。