Flutter: 从入门到渐入佳境
通常我们需要衡量是否值得花精力去学习一个新的东西,但如果你是一个面向全栈(或面向人民币)的有志青年,Flutter作为一个跨端框架是完全值得你去尝试的。在吸收各种前辈的经验(React Native / Weex)后,Flutter提供了一个简洁,有力的形式让你去组织你的跨端App。
安装
下载好SDK配置好环境变量后,你可以用Android Studio,VS Code安装Flutter的插件来获得开发支持。
创建项目后这里你可能遇到的坑可能会有:
gradle在国内下载很慢的问题。这时候只需要修改项目android/build.gradle 里的repositories为阿里云的源即可
1 | maven { url'https://maven.aliyun.com/repository/google' } |
Android NDK环境变量没有配置好。
概览
框架概览
可以看到项目代码主要是用Dart来写的。Dart这个语言很早就出来了,我大概在13年的时候尝试过。Dart2后属于一个强类型的语言,很容易入手,学习难度不会很大。
控件 / Widget
在Flutter中Widget属于构建UI的最小基本元素。
Widget分Stateless / Sateful:
Stateless
这个概念很好理解,有些组件可能初始化之后不会有任何更新。例如一个按钮,一张图表。Sateful:
当你的UI可能需要根据用户的某个交互(点击 / 长按)做出状态变换的时候。
基础控件
Flutter有几个特别常用的基础控件
- Text:创建一段有样式的文本
- Row,Colmun:这两个控件可以让你用web Flex布局模型来构建UI
- Stack: 可以让控件脱离上下文,相对于屏幕上下左右,等同于web里的绝对定位模型
- Container:创建一个矩形元素,等同于web里的div,他有外边距内边距。
一个简单的例子: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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67import 'package:flutter/material.dart';
class MyAppBar extends StatelessWidget {
MyAppBar({this.title});
// Fields in a Widget subclass are always marked "final".
final Widget title;
Widget build(BuildContext context) {
return Container(
height: 56.0, // in logical pixels
padding: const EdgeInsets.symmetric(horizontal: 8.0),
decoration: BoxDecoration(color: Colors.blue[500]),
// Row is a horizontal, linear layout.
child: Row(
// <Widget> is the type of items in the list.
children: <Widget>[
IconButton(
icon: Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null, // null disables the button
),
// Expanded expands its child to fill the available space.
Expanded(
child: title,
),
IconButton(
icon: Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
);
}
}
class MyScaffold extends StatelessWidget {
Widget build(BuildContext context) {
// Material is a conceptual piece of paper on which the UI appears.
return Material(
// Column is a vertical, linear layout.
child: Column(
children: <Widget>[
MyAppBar(
title: Text(
'Example title',
style: Theme.of(context).primaryTextTheme.title,
),
),
Expanded(
child: Center(
child: Text('Hello, world!'),
),
),
],
),
);
}
}
void main() {
runApp(MaterialApp(
title: 'My app', // used by the OS task switcher
home: MyScaffold(),
));
}
基础布局
- 布局一个控件
创建一个内容控件1
Text('Hello World', style: TextStyle(fontSize: 32.0))
所有布局控件都有一个属性叫child(Center / Container)的单个子控件,或者 children(Row,Column, ListView, Stack)拥有多个子控件。
添加一个Text到Center布局控件中
1 | Center( |
- 以水平或垂直方向布局多个控件
在布局有个很重要的东西就是如何把多个控件水平或者垂直放置,你可以用Row来让多个控件按水平布局,用Column来垂直布局多个控件。
- 对齐控件
你可以通过mainAxisAlignment /crossAxisAlignment 来控制一个Row / Cloumn的子控件。
MainAxisAlignment 和 CrossAxisAlignment 提供了一系列常量来控制对齐规则。
让3张图片加起来的宽小于屏幕宽情况下,自适应有间隙的排列
1 | appBar: AppBar( |
如果图片宽度不可预计呢?使用Expanded控,这个控件可以接收一个flex属性来控制单个特定的大小。
1 |
|
可以看到第二张图片比其它的要宽。
内置布局框架
Flutter拥有丰富的布局控件,如常见的GridView,ListView,Stack,Card 可以很快的利用它们来布局。具体细节需要时查阅文档即可!
交互
创建一个Stateful的Widget1
2
3
4class FavoriteWidget extends StatefulWidget {
_FavoriteWidgetState createState() => _FavoriteWidgetState();
}
监听onPressed1
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
43class _FavoriteWidgetState extends State<FavoriteWidget> {
bool _isFavorited = true;
int _favoriteCount = 41;
void _toggleFavorite() {
setState(() {
// If the lake is currently favorited, unfavorite it.
if (_isFavorited) {
_favoriteCount -= 1;
_isFavorited = false;
// Otherwise, favorite it.
} else {
_favoriteCount += 1;
_isFavorited = true;
}
});
}
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.all(0.0),
child: IconButton(
icon: (_isFavorited
? Icon(Icons.star)
: Icon(Icons.star_border)),
color: Colors.red[500],
onPressed: _toggleFavorite,
),
),
SizedBox(
width: 18.0,
child: Container(
child: Text('$_favoriteCount'),
),
),
],
);
}
}
初始化1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
Widget titleSection = Container(
// ...
child: Row(
children: [
Expanded(
child: Column(
// ...
),
FavoriteWidget(),
],
),
);
return MaterialApp(
// ...
);
}
}
导航/路由
大部分情况下我们会有多个页面来显示不同的信息。如在一个List跳到新页面去看详细信息。在Flutter中新页面就是一个Widget,我们可以通过Navigator来控制。
Navigator.push 打开新页面,Navigator.pop 返回。
1 | import 'package:flutter/foundation.dart'; |
以上这个例子展示了一个TodoList点击查看Detail的例子。
至此你可以开始撸跨端的App啦!遇到问题不要方,布局问题可以学习sdk内置的material包,dart 语言问题参考dartlang.org, 善用第三方库!多看flutter.io的文档。
参考:
https://flutter.io/docs/development/ui/widgets-intro
https://flutter.io/docs/reference/widgets
https://docs.flutter.io/
https://pub.dartlang.org/flutter