第3章 - 基础组件
3.1 文本及样式
3.1.1 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,
})
maxLines
,overflow
指定文本显示的最大行数,默认情况下,文本是自动折行的,如果指定此参数,则文本最多不会超过指定的行. 如果有多余的文本,可以通过overflow来指定截断方式,默认是直接截断textScaleFactor
代表文本相对于当前字体大小的缩放因子,相对于去设置文本的样式style属性的fontSize,它是调整字体大小的一个快捷方式. 该属性的默认值可以通过MediaQueryData.textScaleFactor获得,如果没有MediaQuery,那么会默认值将为1.0.
示例
Text("Hello world "*6, //字符串重复六次
textAlign: TextAlign.center,
);
TextStyle
TextStyle
用于指定文本显示的样式如颜色、字体、粗细、背景等:
Text("Hello world",
style: TextStyle(
color: Colors.blue,
fontSize: 18.0,
height: 1.2,
fontFamily: "Courier",
background: Paint()..color=Colors.yellow,
decoration:TextDecoration.underline,
decorationStyle: TextDecorationStyle.dashed
),
);
height
该属性用于指定行高,但它并不是一个绝对值,而是一个因子,具体的行高等于fontSize
*height
.fontFamily
由于不同平台默认支持的字体集不同,所以在手动指定字体时一定要先在不同平台测试一下.fontSize
该属性和 Text 的textScaleFactor
都用于控制字体大小. 但是有两个主要区别:fontSize
可以精确指定字体大小,而textScaleFactor
只能通过缩放比例来控制.textScaleFactor
主要是用于系统字体大小设置改变时对 Flutter 应用字体进行全局调整,而fontSize
通常用于单个文本,字体大小不会跟随系统字体大小变化.
TextSpan
如果我们需要对一个 Text
内容的不同部分按照不同的样式显示,这时就可以使用TextSpan
,它代表文本的一个片段:
const TextSpan({
TextStyle style,
Sting text,
List<TextSpan> children,
GestureRecognizer recognizer,
});
children
是一个TextSpan
的数组,也就是说TextSpan
可以包括其他TextSpan
. 而recognizer
用于对该文本片段上用于手势进行识别处理:
Text.rich(TextSpan(
children: [
TextSpan(
text: "Home: "
),
TextSpan(
text: "https://flutterchina.club",
style: TextStyle(
color: Colors.blue
),
recognizer: _tapRecognizer
),
]
DefaultTextStyle
文本的样式默认是可以被继承的, 如果在 Widget 树的某一个节点处设置一个默认的文本样式(DefaultTextStyle
),那么该节点的子树中所有文本都会默认使用这个样式:
DefaultTextStyle(
//1.设置文本默认样式
style: TextStyle(
color:Colors.red,
fontSize: 20.0,
),
textAlign: TextAlign.start,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("hello world"),
Text("I am Jack"),
Text("I am Jack",
style: TextStyle(
inherit: false, //2.不继承默认样式
color: Colors.grey
),
),
],
),
);
3.2 按钮
Material 提供的按钮组件有:
ElevatedButton
TextButton
OutlineButton
IconButton
它们大部分都是对
RawMaterialButton
组件的包装定制
示例 :
// ElevatedButton, TextButton, OutlineButton 使用方式相同, 仅是样式不同
ElevatedButton(
child: Text("normal"),
onPressed: () {},
);
// icon+文案按钮
ElevatedButton.icon(
icon: Icon(Icons.send),
label: Text("发送"),
onPressed: _onPressed,
)
// Icon按钮
IconButton(
icon: Icon(Icons.thumb_up),
onPressed: () {},
)
3.3 图片及ICON
图片
Flutter中使用 Image
组件加载并显示组件:
const Image({
ImageProvider image,
})
Image
的属性image
对应的类型ImageProvider
是一个抽象类, 主要定义了图片数据获取的方法load()
, 其实现类有:
AssetImage
实现了从Asset中加载图片的ImageProvider
NetworkImage
实现了从网络加载图片的ImageProvider
除了常规的构造函数初始化图片, Image
还提供了对应的便捷的构造方法:
Image(
image: AssetImage("images/avatar.png"),
width: 100.0
);
// 等价于
Image.asset("images/avatar.png",
width: 100.0,
);
Image(
image: NetworkImage("https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
width: 100.0,
);
// 等价于
Image.network(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
width: 100.0,
);
其他参数:
const Image({
...
this.width, //图片的宽
this.height, //图片高度
this.color, //图片的混合色值
this.colorBlendMode, //混合模式
this.fit,//缩放模式
this.alignment = Alignment.center, //对齐方式
this.repeat = ImageRepeat.noRepeat, //重复方式
...
});
width
height
: 用于设置图片的宽、高,当不指定宽高时,图片会根据当前父容器的限制,尽可能的显示其原始大小,如果只设置width、height的其中一个,那么另一个属性默认会按比例缩放,但可以通过下面介绍的fit
属性来指定适应规则.- `fit:该属性用于在图片的显示空间和图片本身大小不同时指定图片的适应模式. 适应模式是在BoxFit中定义,它是一个枚举类型,有如下值:
fill
: 会拉伸填充满显示空间,图片本身长宽比会发生变化,图片会变形.cover
: 会按图片的长宽比放大后居中填满显示空间,图片不会变形,超出显示空间部分会被剪裁.contain
: 这是图片的默认适应规则,图片会在保证图片本身长宽比不变的情况下缩放以适应当前显示空间,图片不会变形.fitWidth
: 图片的宽度会缩放到显示空间的宽度,高度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁.fitHeight
: 图片的高度会缩放到显示空间的高度,宽度会按比例缩放,然后居中显示,图片不会变形,超出显示空间部分会被剪裁.none
: 图片没有适应策略,会在显示空间内显示图片,如果图片比显示空间大,则显示空间只会显示图片中间部分.
color
和colorBlendMode
: 在图片绘制时可以对每一个像素进行颜色混合处理,color指定混合色,而colorBlendMode指定混合模式repeat
: 当图片本身大小小于显示空间时,指定图片的重复规则
3.4 单选开关和复选框
单选开关Switch
, 复选框Checkbox
, 当 Switch
或 Checkbox
被点击时,会触发 onChanged
回调, 我们可以在此回调中处理选中状态改变逻辑.
Checkbox
有一个属性tristate
, 表示是否为三态, tristate
为fase时, Checkbox
有两种状态即“选中”和“不选中”,对应的 value 值为true和false; 如果tristate
值为true时,value 的值会增加一个状态null. 默认情况下该属性值为false:
bool? _checked;
Checkbox(
value: _checked,
activeColor: Colors.red,
tristate: true,
onChanged: (val) {
setState(() {
_checked = val;
});
}),
Text("$_checked") // 会有三种值: null, true, false
3.5 输入框及表单
TextField
TextField
用于文本输入, 关键属性如下:
const TextField({
...
// 编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件. 如果没有提供controller,则TextField内部会自动创建一个.
TextEditingController controller,
// 用于控制TextField是否占有当前键盘的输入焦点. 它是我们和键盘交互的一个句柄(handle)
// 比如收起键盘
FocusNode focusNode,
// 用于控制TextField的外观显示,如提示文本、背景颜色、边框等
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType, // 用于设置该输入框默认的键盘输入类型
TextInputAction textInputAction, // 键盘动作按钮图标(即回车键位图标),它是一个枚举值
TextStyle style, // 正在编辑的文本样式
TextAlign textAlign = TextAlign.start, // 输入框内编辑文本在水平方向的对齐方式
bool autofocus = false, // 是否自动获取焦点
bool obscureText = false, // 是否隐藏正在编辑的文本,如用于输入密码的场景等
int maxLines = 1, // 输入框的最大行数,默认为1;如果为null,则无行数限制
int maxLength, // 代表输入框文本的最大长度,设置后输入框右下角会显示输入的文本计数
this.maxLengthEnforcement, // 决定当输入文本长度超过maxLength时如何处理,如截断、超出等
// 长按或鼠标右击时出现的菜单
// 包括 copy、cut、paste 以及 selectAll
ToolbarOptions? toolbarOptions,
// 输入框内容改变时的回调函数, 内容改变事件也可以通过controller来监听
ValueChanged<String> onChanged,
// 输入框输入完成时触发, 回调函数不接受参数
VoidCallback onEditingComplete,
// 输入框输入完成时触发, 回调是ValueChanged<String>类型
ValueChanged<String> onSubmitted,
// 用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验
List<TextInputFormatter> inputFormatters,
// 如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)
bool enabled,
// 以下三个 cursorXXX 属性是用于自定义输入框光标宽度、圆角和颜色的
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.onTap,
...
})
keyboardType 可选值如下:
TextInputType 枚举值 | 含义 |
---|---|
text | 文本输入键盘 |
multiline | 多行文本,需和maxLines配合使用(设为null或大于1) |
number | 数字;会弹出数字键盘 |
phone | 优化后的电话号码输入键盘;会弹出数字键盘并显示: * # |
datetime | 优化后的日期输入键盘;Android上会显示: : - |
emailAddress | 优化后的电子邮件地址, 会显示: @ . |
url | 优化后的url输入键盘, 会显示: / . |
示例:
String _text = ""; // 存放用户在文本框输入的内容
TextField(
style: TextStyle(color: Colors.green),
toolbarOptions: ToolbarOptions(
copy: true,
),
decoration: InputDecoration(
labelText: "用户名",
hintText: "手机号或邮箱",
prefixIcon: Icon(Icons.person)),
onChanged: (val) {
setState(() {
_text = val;
});
},
)
控制焦点
焦点可以通过FocusNode
和FocusScopeNode
来控制:
FocusNode focusNode1 = FocusNode();
TextField(
autofocus: true,
focusNode: focusNode1, // 关联focusNode1
)
// 焦点移动到文本框, 同时会打开键盘
FocusScope.of(context).requestFocus(focusNode1);
// 从文本框移除焦点, 同时会收起键盘
focusNode1.unfocus();
实例 - 隐藏手机号中间4位
下面演示一个手机号中间加*的文本框状态实现:
class _TextFieldWidgetState extends State<TextFieldWidget> {
String _fullPhone = "";
final FocusNode _focus = FocusNode();
final TextEditingController _controller = TextEditingController();
@override
void initState() {
this._focus.addListener(() {
if (this._focus.hasFocus) {
// 用户光标聚焦在文本框
this._controller.text = this._fullPhone;
} else {
// 用户光标离开文本框
// 如果文本框内容是11位, 把中间4位隐藏掉, 并更新到文本框内容上
// 这里应该用正则判断手机号更加严谨
final String currentValue = this._controller.text;
setState(() {
this._fullPhone = currentValue;
});
if (currentValue.length == 11) {
final String maskPhone =
currentValue.substring(0, 3) + "****" + currentValue.substring(7);
this._controller.text = maskPhone;
}
}
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
padding: EdgeInsets.only(left: 50, right: 50),
child: TextField(
controller: this._controller,
focusNode: this._focus,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: "用户名",
hintText: "请输入手机号",
prefixIcon: Icon(Icons.phone)),
),
),
],
);
}
}
- 作者: 杜文 wendux
- 原文: https://book.flutterchina.club
- 本文仅用于本人学习和存档, 文章所有权归作者 杜文 wendux 所有, 如有侵权请发送邮件至 me#alanwei.com(#换成@) 删除此文.