本文学习和引用自《Flutter实战·第二版》:作者:杜文
// 字符串重复4次
Text("Hello world"*4,
// 左对齐
textAlign: TextAlign.left,
// 指定文本显示的最大行数
maxLines: 1,
// 文本截断后以省略符表示
overflow: TextOverflow.ellipsis,
// 相对于当前字体大小的缩放因子
textScaleFactor: 1.5
);
Text("Hello world!",
style: TextStyle(
color: Colors.blue,
fontSize: 18.0,
// 行高 等于fontSize * height
height: 1.2,
// 字体
fontFamily: "Courier",
background: Paint()..color=Colors.yellow,
// 下划线
decoration:TextDecoration.underline,
// 下划线样式
decorationStyle: TextDecorationStyle.dashed
),
);
Text.rich(
TextSpan(
children: [
TextSpan(
text: "链接: "
),
TextSpan(
text: "https://pub.dev.com",
style: TextStyle(
color: Colors.blue
),
recognizer: () => {
print('xxyyxx')
}
),
]
)
)
// 设置文本默认样式
DefaultTextStyle(
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,
color: Colors.grey
),
),
],
),
)
字体首先要在pubspec.yaml中声明它们,以确保它们会打包到应用程序中。然后通过TextStyle属性使用字体。
flutter:
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: assets/fonts/Raleway-Medium.ttf
weight: 500
- asset: assets/fonts/Raleway-SemiBold.ttf
weight: 600
- family: AbrilFatface
fonts:
- asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf
// 声明文本样式
const textStyle = const TextStyle(
fontFamily: 'Raleway',
// 假设上面的字体声明位于my_package包中 则需要指定包名
package: 'my_package'
);
// 使用文本样式
var buttonText = const Text(
"Use the font for this text",
style: textStyle,
);
Material 组件库中提供了多种按钮组件。他们都有如下特性:
// 默认带有阴影和灰色背景。按下后,阴影会变大
ElevatedButton(
child: Text("normal"),
onPressed: () {},
)
// 默认背景透明并不带阴影。按下后,会有背景色
TextButton(
child: Text("normal"),
onPressed: () {},
)
// 默认有一个边框,不带阴影且背景透明。按下后,边框颜色会变亮、同时出现背景和较弱的阴影
OutlinedButton(
child: Text("normal"),
onPressed: () {},
)
// 可点击的Icon,不包括文字,默认没有背景,点击后会出现背景
IconButton(
icon: Icon(Icons.thumb_up),
onPressed: () {},
)
ElevatedButton.icon(
icon: Icon(Icons.send),
label: Text("发送"),
onPressed: () {},
)
OutlinedButton.icon(
icon: Icon(Icons.add),
label: Text("添加"),
onPressed: () {},
)
TextButton.icon(
icon: Icon(Icons.info),
label: Text("详情"),
onPressed: () {},
)
Flutter 中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络资源。
ImageProvider:一个抽象类,主要定义了图片数据获取的接口load(),从不同的数据源获取图片需要实现不同的ImageProvider ,如AssetImage是实现了从Asset中加载图片的 ImageProvider,而NetworkImage 实现了从网络加载图片的 ImageProvider。
Image:Image widget 有一个必选的image参数,它对应一个 ImageProvider。
先在pubspec.yaml文件中flutter部分添加assets资源路径
Image(
image: AssetImage("static/portrait.png"),
width: 100.0
);
// or
Image.asset("static/portrait.png",
width: 100.0,
)
Image(
image: NetworkImage(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
width: 100.0,
)
// or
Image.network(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
width: 100.0,
)
属性 | 值 | 描述 |
---|---|---|
width | - | 宽度 |
height | - | 高度 |
fit | fill、cover、contain、fitWidth、fitHeight、none | 适应模式 |
color | - | 混合色 |
colorBlendMode | - | 混合模式 |
repeat | - | 指定图片的重复规则 |
Flutter 中,可以像Web开发一样使用iconfont字体图标。Flutter默认包含了一套Material Design的(字体图标)[https://material.io/tools/icons/],在pubspec.yaml文件中的配置如下:
flutter:
uses-material-design: true
String icons = "";
// accessible: 0xe03e
icons += "\uE03e";
// error: 0xe237
icons += " \uE237";
// fingerprint: 0xe287
icons += " \uE287";
Text(
icons,
style: TextStyle(
fontFamily: "MaterialIcons",
fontSize: 24.0,
color: Colors.green,
),
);
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.accessible,color: Colors.green),
Icon(Icons.error,color: Colors.green),
Icon(Icons.fingerprint,color: Colors.green),
],
)
首先导入字体图标文件:
fonts:
- family: myIcon # 指定一个字体名
fonts:
- asset: fonts/iconfont.ttf
定义一个MyIcons类,功能和Icons类一样,将字体文件中的所有图标都定义成静态变量:
class MyIcons{
// book 图标
static const IconData book = const IconData(
0xe614,
fontFamily: 'myIcon',
matchTextDirection: true
);
// 微信图标
static const IconData wechat = const IconData(
0xec7d,
fontFamily: 'myIcon',
matchTextDirection: true
);
}
使用
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MyIcons.book,color: Colors.purple),
Icon(MyIcons.wechat,color: Colors.green),
],
)
Material 组件库中提供了 Material 风格的单选开关Switch和复选框Checkbox。但它们本身不会保存当前选中状态,选中状态都是由父组件来管理的。
class SwitchAndCheckBoxTestRoute extends StatefulWidget {
_SwitchAndCheckBoxTestRouteState createState() => _SwitchAndCheckBoxTestRouteState();
}
class _SwitchAndCheckBoxTestRouteState extends State<SwitchAndCheckBoxTestRoute> {
// 维护单选开关状态
bool _switchSelected = true;
// 维护复选框状态
bool _checkboxSelected=true;
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Switch(
// 当前状态
value: _switchSelected,
onChanged:(value){
// 重新构建页面
setState(() {
_switchSelected=value;
});
},
),
Checkbox(
value: _checkboxSelected,
// 选中时的颜色
activeColor: Colors.red,
onChanged:(value){
setState(() {
_checkboxSelected=value;
});
},
)
],
);
}
}
Checkbox的大小是固定的,无法自定义,而Switch只能定义宽度,高度也是固定的。
Material 组件库中提供了输入框组件TextField和表单组件Form
TextField用于文本输入
Form 组件,它可以对输入框进行分组,然后进行一些统一操作,如输入内容校验、输入框重置以及输入内容保存。Form继承自StatefulWidget对象,它对应的状态类为FormState,Form的子孙元素必须是FormField类型,为了方便使用,Flutter 提供了一个TextFormField组件,它继承自FormField类,也是TextField的一个包装类,所以除了FormField定义的属性之外,它还包括TextField的属性。
属性 | 描述 |
---|---|
autovalidate | 是否自动校验输入内容,默认为false,即只有点击操作按钮时才校验 |
onWillPop | 决定Form所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个Future对象,如果 Future 的最终结果是false,则当前路由不会返回;如果为true,则会返回到上一个路由。此属性通常用于拦截返回按钮 |
onChanged | Form内容改变时的回调函数,可以用于对输入内容进行校验。 |
FormState是Form的State类,可以通过Form.of()或GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作,常用方法如下:
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
State<LoginPage> createState() {
return LoginPageState();
}
}
class LoginPageState extends State<LoginPage> {
TextEditingController userName = TextEditingController();
TextEditingController password = TextEditingController();
final formKey = GlobalKey<FormState>();
void handleSubmit() {
if ((formKey.currentState as FormState).validate()) {
if (userName.text.length >= 6 && password.text.length >= 6) {
// 提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('验证通过!')),
);
} else {
// 清除内容
formKey.currentState?.reset();
// 提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('账号和密码长度不能低于6位数!')),
);
}
} else {
debugPrint('校验失败!');
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Login Page'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
autofocus: false,
controller: userName,
decoration: const InputDecoration(
labelText: "账号:",
hintText: "请输入账号",
icon: Icon(Icons.person),
),
validator: (v) {
return v!.trim().isNotEmpty ? null : '账号不能为空';
},
),
TextFormField(
autofocus: false,
controller: password,
decoration: const InputDecoration(
labelText: "密码:",
hintText: "请输入密码",
icon: Icon(Icons.lock),
),
obscureText: true,
validator: (v) {
return v!.trim().isNotEmpty ? null : '密码不能为空';
},
),
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ElevatedButton(
onPressed: handleSubmit,
child: const Padding(
padding: EdgeInsets.all(16.0),
child: Text('登录'),
),
),
),
)
],
),
)
],
),
);
}
}
Material 组件库中提供了两种进度指示器:LinearProgressIndicator和CircularProgressIndicator,它们都可以同时用于精确的进度指示和模糊的进度指示。
LinearProgressIndicator 是一个线性进度条,它显示一个进度条,可以显示当前的进度和总进度。没有提供尺寸参数,都是取父容器的尺寸作为绘制的边界,也就是父容器的宽高。
// 模糊进度条(会执行一个动画)
LinearProgressIndicator(
backgroundColor: Colors.grey[200],
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
// 进度条显示50%
LinearProgressIndicator(
backgroundColor: Colors.grey[200],
valueColor: AlwaysStoppedAnimation(Colors.blue),
value: .5,
)
CircularProgressIndicator 是一个环形进度条,它显示一个进度条,可以显示当前的进度和总进度。没有提供尺寸参数,都是取父容器的尺寸作为绘制的边界,也就是父容器的宽高。
// 模糊进度条(会执行一个旋转动画)
CircularProgressIndicator(
backgroundColor: Colors.grey[200],
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
// 进度条显示50%,会显示一个半圆
CircularProgressIndicator(
backgroundColor: Colors.grey[200],
valueColor: AlwaysStoppedAnimation(Colors.blue),
value: .5,
),
本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~
往期文章
个人主页