主题
Flutter实现了一套漂亮的MD(Material Design)组件,可以定制许多样式和主题。在Main函数中使用声明的顶级widget,MaterialApp作为程序入口。(类似于iOS中需要声明在Appdelegate中设置window的rootController作为iOS应用入口)。
MaterialApp在Flutter中是一个非常便利的组件,包含了许多App通常需要的MD风格组件,它通过一个WidgetsApp添加了MD功能来实现。类似的,在WidgetApp中也提供了许多相似功能,但是没有MaterialApp强大,所以推荐使用MaterialApp组件。
在iOS上可以用Cupertino library来制作遵守Human Interface Guidelines的界面。可以查看Cupertino widgets gallery来了解这些widget的集合。
在MaterialApp中可以设置ThemeData对象,来自定义主题颜色和样式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MaterialSampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
// 设置主题色是蓝色
primarySwatch: Colors.blue,
// 设置文字选中时为红色
textSelectionColor: Colors.red,
),
home: MaterialSampleAppPage(),
);
}
}
自定义字体
在Flutter中使用自定义字,跟iOS一样需要把字体库放到工程路径下的文件夹中,但是Flutter需要在pubspec.yaml中添加引用,可以参考图片资源的引用。
1
2
3
4
5
fonts:
- family: MyCustomFont
fonts:
- asset: fonts/MyCustomFont.ttf
- style: italic
使用字体:
1
2
3
4
child: Text(
'This is a custom font text',
style: TextStyle(fontFamily: 'MyCustomFont'),
),
使用iconfont,一样需要pubspec.yaml文件添加引用,然后使用方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MaterialSampleAppPage extends StatelessWidget {
const MaterialSampleAppPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Theme'),
),
body: Center(
// child: Text(
// '自定义字体 Custom Font',
// style: TextStyle(fontFamily: 'your font family', fontSize: 20),
// ),
child: Icon(
// 使用iconfont
IconData(
0xea74,
fontFamily:'iconfont',
),
color: Colors.red,
size: 100,
)
),
);
}
}
字体样式
除了字体意外,还可以给Text widget的样式元素设置自定义值。通过在Text的TextStyle对象来设置,可设置参数:
- color
- decoration
- decorationColor
- decorationStyle
- fontFamily
- fontSize
- fontStyle
- fontWeight
- hashCode
- height
- inherit
- letterSpacing
- textBaseline
- wordSpacing
表单输入
FLutter中使用的widget是不可变的,并且状态是分离的,所以使用表单需要通过特定的widget来完成表单操作。例如TextField或TextFormField,使用TextEditingController获取用户输入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class _FormSampleAppPageState extends State<FormSampleAppPage> {
// 创建表单
final formController = TextEditingController();
@override
void dispose() {
// TODO: implement dispose
formController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
appBar: AppBar(
title: Text('表单输入'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: formController,
style: TextStyle(
color: Colors.red
),
),
),
floatingActionButton: FloatingActionButton(
// 用户点击时显示
onPressed: () {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('输入内容'),
content: Text(formController.text),
);
}
);
},
tooltip: '点击',
child: Icon(Icons.text_fields),
),
),
);
}
}
可以通过向Text widget的装饰构造器函数传入InputDecoration
来展示提示文字(placeholder):
1
2
3
4
5
body: Center(
child: TextField(
decoration: InputDecoration(hintText: "This is a hint"),
),
)
错误信息展示
在InputDecoration对象中传入errorText,可以展示错误信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class _FormSampleAppPage extends StatefulWidget {
_FormSampleAppPage({Key key}) : super(key: key);
__FormSampleAppPageState createState() => __FormSampleAppPageState();
}
class __FormSampleAppPageState extends State<_FormSampleAppPage> {
String _errorText;
void showError(text) {
setState(() {
if (!isEmail(text)) {
_errorText = 'Error, This is not email.';
} else {
_errorText = null;
}
});
}
bool isEmail(text) {
// 正则匹配
String emailRegexp = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regExp = RegExp(emailRegexp);
return regExp.hasMatch(text);
}
_getErrorText() {
print(_errorText);
return _errorText;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('表单'),
),
body: Center(
child: TextField(
onSubmitted: (String text) {
showError(text);
print('提交');
},
decoration: InputDecoration(
hintText: '请输入一个email',
errorText: _getErrorText()
),
),
),
);
}
}