本节目标

  • 了解 supernova 代码生成器作用
  • 导入 xd 设计稿
  • 如何高效使用生成代码

视频

代码

https://github.com/ducafecat/flutter_learn_news/releases/tag/v1.0.13

正文

代码生成器

有潜力加入代码生成功能

supernova 代码生成器

https://supernova.io/

导入 xd 设计稿,生成代码

商业设计稿不好直接分享, 可以加微信联系 ducafecat

编写用户中心界面代码

组织代码结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class _AccountPageState extends State<AccountPage> {
// 个人页面 头部
Widget _buildUserHeader() {}

// 列表项
Widget _buildCell() {}

@override
Widget build(BuildContext context) {
final appState = Provider.of<AppState>(context);

return SingleChildScrollView(
child: Column(
children: <Widget>[
_buildUserHeader(),
_buildCell(),
],
),
);
}
}

直接使用生成的代码

  • 个人页面 头部
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
Widget _buildUserHeader() {
return Container(
height: 333,
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 0,
right: 0,
child: Container(
height: 333,
decoration: BoxDecoration(
color: AppColors.primaryBackground,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 2,
decoration: BoxDecoration(
color: AppColors.primaryElement,
),
child: Container(),
),
],
),
),
),
Positioned(
left: 20,
top: 40,
right: 20,
bottom: 21,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 198,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Align(
alignment: Alignment.topCenter,
child: Container(
width: 108,
height: 108,
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
top: 0,
child: Container(
width: 108,
height: 108,
decoration: BoxDecoration(
color: AppColors.primaryBackground,
boxShadow: [
Shadows.primaryShadow,
],
borderRadius: Radii.k54pxRadius,
),
child: Container(),
),
),
Positioned(
top: 10,
child: Image.asset(
"assets/images/image.png",
fit: BoxFit.none,
),
),
],
),
),
),
Spacer(),
Container(
margin: EdgeInsets.only(bottom: 9),
child: Text(
"Cameron Rogers",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: 24,
),
),
),
Text(
"@boltrogers",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenir",
fontWeight: FontWeight.w400,
fontSize: 16,
),
),
],
),
),
Spacer(),
Container(
height: 44,
child: FlatButton(
onPressed: () => this.onButtonPressed(context),
color: Color.fromARGB(255, 41, 103, 255),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6)),
),
textColor: Color.fromARGB(255, 255, 255, 255),
padding: EdgeInsets.all(0),
child: Text(
"Get Premium - \$9.99",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.secondaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: 18,
),
),
),
),
],
),
),
],
),
);
}
  • 列表项
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
Widget _buildCell() {
return Container(
height: 60,
child: Stack(
alignment: Alignment.centerLeft,
children: [
Positioned(
left: 0,
right: 0,
child: Container(
height: 60,
decoration: BoxDecoration(
color: AppColors.secondaryElement,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 1,
decoration: BoxDecoration(
color: AppColors.primaryElement,
),
child: Container(),
),
],
),
),
),
Positioned(
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
margin: EdgeInsets.only(right: 11),
child: Text(
"12",
textAlign: TextAlign.right,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenir",
fontWeight: FontWeight.w400,
fontSize: 18,
),
),
),
Container(
width: 24,
height: 24,
margin: EdgeInsets.only(right: 20),
child: Image.asset(
"assets/images/icon.png",
fit: BoxFit.none,
),
),
],
),
),
Positioned(
left: 0,
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 0,
right: 19,
child: Container(),
),
Positioned(
left: 20,
right: 0,
child: Text(
"Favorite channels",
textAlign: TextAlign.left,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: 18,
),
),
),
],
),
),
],
),
);
}

抽取代码 lib/common/widgets/app.dart

1
2
3
4
5
6
7
8
9
/// 10像素 Divider
Widget divider10Px({Color bgColor = AppColors.secondaryElement}) {
return Container(
height: duSetWidth(10),
decoration: BoxDecoration(
color: bgColor,
),
);
}

修改代码 _buildUserHeader

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 个人页面 头部
Widget _buildUserHeader() {
return Container(
height: duSetWidth(333),
child: Stack(
alignment: Alignment.center,
children: [
// 背景
Positioned(
left: 0,
right: 0,
child: Container(
height: duSetWidth(333),
decoration: BoxDecoration(
color: AppColors.primaryBackground,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: duSetWidth(2),
decoration: BoxDecoration(
color: AppColors.tabCellSeparator,
),
child: Container(),
),
],
),
),
),
Positioned(
left: 20,
top: 40,
right: 20,
bottom: 21,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 头像
Container(
height: duSetWidth(198),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Align(
alignment: Alignment.topCenter,
child: Container(
width: duSetWidth(108),
height: duSetWidth(108),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
top: 0,
child: Container(
width: duSetWidth(108),
height: duSetWidth(108),
decoration: BoxDecoration(
color: AppColors.primaryBackground,
boxShadow: [
Shadows.primaryShadow,
],
borderRadius: BorderRadius.all(
Radius.circular(duSetWidth(108) / 2)),
),
child: Container(),
),
),
Positioned(
top: 10,
child: Image.asset(
"assets/images/account_header.png",
height: duSetWidth(88),
width: duSetWidth(88),
fit: BoxFit.fill,
),
),
],
),
),
),
// 文字
Spacer(),
Container(
margin: EdgeInsets.only(bottom: 9),
child: Text(
Global.profile.displayName,
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: 24,
),
),
),
Text(
"@boltrogers",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenir",
fontWeight: FontWeight.w400,
fontSize: 16,
),
),
],
),
),
// 按钮
Spacer(),
Container(
height: 44,
child: FlatButton(
onPressed: () => {},
color: Color.fromARGB(255, 41, 103, 255),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6)),
),
textColor: Color.fromARGB(255, 255, 255, 255),
padding: EdgeInsets.all(0),
child: Text(
"Get Premium - \$9.99",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryElementText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: 18,
),
),
),
),
],
),
),
],
),
);
}

修改代码 _buildCell

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

// 列表项
Widget _buildCell({
String title,
String subTitle,
int number,
bool hasArrow = false,
VoidCallback onTap,
}) {
return GestureDetector(
onTap: onTap,
child: Container(
height: duSetWidth(60),
color: Colors.white,
child: Stack(
alignment: Alignment.centerLeft,
children: [
// 背景
Positioned(
left: 0,
right: 0,
child: Container(
height: duSetWidth(60),
decoration: BoxDecoration(
color: AppColors.primaryBackground,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: duSetWidth(1),
decoration: BoxDecoration(
color: AppColors.tabCellSeparator,
),
child: Container(),
),
],
),
),
),
// 右侧
Positioned(
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// 数字
number == null
? Container()
: Container(
margin: EdgeInsets.only(right: 11),
child: Text(
number.toString(),
textAlign: TextAlign.right,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenir",
fontWeight: FontWeight.w400,
fontSize: duSetFontSize(18),
),
),
),
// 箭头
hasArrow == false
? Container()
: Container(
width: duSetWidth(24),
height: duSetWidth(24),
margin: EdgeInsets.only(right: 20),
child: Icon(
Icons.arrow_forward_ios,
color: AppColors.primaryText,
),
),
],
),
),

// 标题
title == null
? Container()
: Positioned(
left: 20,
child: Text(
title,
textAlign: TextAlign.left,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: duSetFontSize(18),
),
),
),

// 子标题
subTitle == null
? Container()
: Positioned(
right: 20,
child: Text(
subTitle,
textAlign: TextAlign.left,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w400,
fontSize: duSetFontSize(18),
),
),
),
],
),
),
);
}

修改代码 build

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

@override
Widget build(BuildContext context) {
final appState = Provider.of<AppState>(context);

return SingleChildScrollView(
child: Column(
children: <Widget>[
_buildUserHeader(),
divider10Px(),
_buildCell(
title: "Email",
subTitle: "boltrogers@gmail.com",
),
divider10Px(),
_buildCell(
title: "Favorite channels",
number: 12,
hasArrow: true,
),
_buildCell(
title: "Bookmarks",
number: 294,
hasArrow: true,
),
_buildCell(
title: "Popular categories",
number: 7,
hasArrow: true,
),
divider10Px(),
_buildCell(
title: "Newsletter",
hasArrow: true,
),
_buildCell(
title: "Settings",
hasArrow: true,
),
divider10Px(),
_buildCell(
title: "Switch Gray Filter",
hasArrow: true,
onTap: () => appState.switchGrayFilter(),
),
_buildCell(
title: "Log out",
hasArrow: true,
onTap: () => goLoginPage(context),
),
divider10Px(),
],
),
);
}

技巧

  • vscode 固定代码

总结

资源

设计稿蓝湖预览

https://lanhuapp.com/url/lYuz1
密码: gSKl

蓝湖现在收费了,所以查看标记还请自己上传 xd 设计稿
商业设计稿文件不好直接分享, 可以加微信联系 ducafecat


© 猫哥

https://ducafecat.tech