flutter基础学习

最近学习了一周flutter,做了一下笔记,之前看到一个推荐入门的视频,初步看了一下很不错,推荐给大家。全新升级小码哥Flutter实战教学完整版附资料 ,如果有Android和IOS原生开发经验的感觉学起来是相对好理解一点。最后面也分享一下写的一个页面代码,由于最近一周公司内部的业务笔记多相对较忙,然后断断续续的学。

1、stl 回车快捷键创建 StatelessWidget

2、如果像IOS UITableViewCell中子视图设置间距的话,可以使用SizeBox(height: 8),就是设置上下之前的控件距离8个像素,
有点类似IOS ToolBar中添加多个item时的 UIBarButtonSystemItemFlexibleSpace.

3、去掉APP展示debug LOGO时在启动 MaterialAPP内 使用debugShowCheckedModeBanner: false

4、 关于widget 有状态的Widget:StatefulWidget在运行过程中有一些状态data数据需要改变,无状态的widget:StatelessWidget内容是确定的没有状态data数据的改变。

5、两个组件widget并排时用Row组件可以放多个组件,想要水平居中,使用Center组件包裹。想要Row里面的子元素在父widget x轴居中 使用mainAxisAlignment: MainAxisAlignment.center.

6、想要子元素垂直流水布局使用Cloumn组件,也是widget但是如果里面的元素超出手机最大长度,就是不能滚动的区域,会展示黄色条纹斑马线的多余区域,解决办法就是使用ListView 可滚动的widget。

7、使用网络加载图片Image.network(url)

8、statelessWidget里的属性必须是不可修改的 用final修饰。并且是实现构造函数就是当前类型传进去的命名的各个参数。

9、如果使用Checkbox组件有按钮点击回调参数如 onChangeed:(value) =>flag = value.

10、@immutable注解标明的类或者子类都必须是不可变的。所以比如statelessWidget类的属性用final修饰。

11、StatefullWidget继承自StatefulWidget的类(可以接受父Widget传过来的数据/state类(状态))。StatefulWidget 要实现 createState()方法,然后实现State类 这个类就是实现可变的属性。

12、如果实现边框和内间距可以使用Container,alt + enter 快捷键可实现一个Widget快速包裹一个Container. Container其中有一个属性decoration翻译过来为装饰,BoxDecoration(border: Border.all( width: 5,//设置边框的宽度, color: Colors.purple//设置边框的颜色))。如果设置Container内间距(子视图到Container的内部间距) padding: EdgeInsets.all(8) 上下左右为8个像素的间距。

13、Text组件中的textAlign相当于IOS中的UILable中的属性textAlignment

14、Column中属性主轴和交叉轴 mainAxisAlignment: MainAxisAlignment.center 交叉轴crossAxisAlignment: CrossAxisAlignment.start(就是开始元素在) Column中开始最左边显示。如果CrossAxisAlignment.end 从右边开始显示相当于。(Column垂直方向就是主轴,Row来说水平方向是主轴).

14、一个类中如果有@protected 如: createState()修饰表示该方法是必须实现的。widget类是不加下划线的,暴露给别人使用,State是加下划线的,状态这个类只给widget使用。为什么Flutter在设计的时候StatefulWidget的build方法放在State中?原因有 一、build出来的Widget是需要依赖State中的变量(状态/数量) 二、在运行的过程中 widget是不断的销毁和创建的。当自己的状态发生改变时,并不希望重新创建一个新的State类。

15、RaisedButton按钮组件 Raisebutton( child; Icon(Icons.add)),onPressed:()=> print("点击+")) Icon是展示图标。

16、如果在State状态类中想可变的参数和不可变的参数(接受StatefulWidget的值时),State本身会持有所归属的widget组件,所以在StatefulWidget类中之间申请属性然后直接可以使用${widget.message} 这儿的widget就是前面自定义的StatefulWidget组件 message属性就是自定义的StatefulWidget类的属性。

17、StatelessWidget的生命周期: 只有本身的构造方法和build(BuildContext context)方法。
StatefulWidget 的生命周期包括两个类widget和state,其中StatefulWidget的生命周期是ConstructorWidget.createState(). State类生命周期 先调用Constructor(构造方法)、initState(初始化状态)、didChangeDependencies(状态值发生改变的时候)、builddispose(销毁方法),这儿如果子类中实现了initState方法,这个方法在父内中是@mustCallSuper意思是自内必须调用的。调用会对父类做一些初始化,同理dispose方法也是一样子。

18、state类里调用setState(VoidCallback fn),会去先执行fn(),然后setState里会去执行markneedsBuild()方法,然后去执行build(),刷新UI。

19、带边框的按钮OutlineButton、平坦的按钮FlatButton、浮动按钮FloatingActionButton(child: Icon(Icons.add),onPressed:()=>)、凸出的按钮RaiseButton.

20、当自定义按钮时FlatButton(color: Colors.red,child: Row(mainAxisSize: MainAxisSize.max,children: <widget>[Icon(Icons.favorite,color: Colors.red,),Text("A")]),onPressed:(){}), mainAxisSize 主轴上的大小。

21、FlatButton使用圆角时shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))

22、加载图片Image(image: NetworkImage("https://~")),width: 200,height:200,fit:BoxFit.fitWidth,alignment: Alignment.BottomCenter)。其中如果设置了图片的背景颜色是会覆盖在最上层,不过可以设置颜色混入模式与图片融合一体,color: Colors.red,colorBlendMode: BlendMode.colorDodge.

23、加载本地图片Image(image: AssetImage("")),这个里面的图片路径有3个步骤,1、在项目中创建一个文件夹,存储图片 2、在pubspec.yaml进行配置 3、使用图片 如pubspec里的配置 assets: - assets/images/ 这儿后面的可以不写图片名字,就加载所有这个images目录的图片资源,然后在使用的时候Image(image: AssetImage("assets/images/图片名字.png")).

24、FlatButton按钮如果再Column中会自动展示 48px间距,如果不足48px会自动填充48 padded,如果想去掉使用,FlatButton(Flatbutton(color: Colors.red,materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,child: Text("Flot Button"),textColor: Colors.white,onPressed:(){})).

25、将StatelessWidget转 StatefulWidget 鼠标选中需要转换的类名,或光标放到类名之间 option + enter,抽取代码为单独的Widget 有时候代码嵌套太多,不方便阅读,抽取Widget为一个单独的类,提高代码的阅读性 鼠标选中需要转换的类名,或光标放到类名之间command + option + W

26、初始化函数 Person(this.name,{int age}):this.age = age ?? 10{}

27、decoration = decoration ?? (color != null ? BoxDecorayion(color: color):null)就是一个赋值语句,意思就是decoration不为空就用这个值,否则就用后面的值。

一个注册页面

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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:pro_summary/utils/util.dart';

class WSLoginPage extends StatefulWidget {
const WSLoginPage({Key? key}) : super(key: key);

@override
_WSLoginPageState createState() => _WSLoginPageState();
}

class _WSLoginPageState extends State<WSLoginPage> {
final themeColor = const Color.fromRGBO(250, 250, 250, 1);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("注册", style: TextStyle(color: Colors.black)),
backgroundColor: themeColor,
elevation: 0, //默认为4 设置成零就没有阴影
//设置主题颜色无效
/*iconTheme: IconThemeData(
color: themeColor,
),*/
//修改返回按钮的颜色
leading: BackButton(color: Colors.grey.withOpacity(0.5)),
),
backgroundColor: themeColor,
body: WSContentBody());
}
}

class WSContentBody extends StatefulWidget {
const WSContentBody({Key? key}) : super(key: key);

@override
State<WSContentBody> createState() => _WSContentBodyState();
}

class _WSContentBodyState extends State<WSContentBody> {
@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.fromLTRB(15, kToolbarHeight, 15, 0),
children: [
Expanded(
child: Column(children: [
BoxCellContainer(
"请输入邀请码", Toast2.loadImage("icon_inputbox_recommend"), 0),
BoxCellContainer(
"请输入11位手机号码", Toast2.loadImage("icon_inputbox_phone"), 1),
BoxCellContainer(
"请输入验证码", Toast2.loadImage("icon_inputbox_code"), 2),
const SizedBox(height: 38),
getNextBtn()
] //下一步按钮,
),
),
const SizedBox(height: 350),
buildBottomRich()
],
);
}

/*构建底部富文本*/
buildBottomRich() {
return Expanded(
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
SizedBox(
width: 34,
height: 34,
child: FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
splashColor: Colors.white10,
highlightColor: Colors.white,
padding:
const EdgeInsets.only(left: 0, top: 0, right: 0, bottom: 18),
child: Image(
width: 14,
height: 14,
image: AssetImage(Toast2.loadImage("btn_bottom_agree_nor")),
fit: BoxFit.contain),
//color: const Color.fromRGBO(153, 153, 153, 0.3),
//textColor: Colors.white,
onPressed: () {}),
),
RichText(
textAlign: TextAlign.justify,
maxLines: 2,
text: TextSpan(
//协议说明文案
text: "阅读并同意",
style: const TextStyle(color: Colors.grey),
children: [
// Expanded(child: )
TextSpan(
text: "《喔刷伙伴Pro支付经销商协议》",
style: const TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
opendUserProtocol();
},
),
const TextSpan(
text: "\n与", style: TextStyle(color: Colors.grey)),
TextSpan(
text: "《隐私协议》",
style: const TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () {
opendUserProtocol();
},
)
]))
]),
);
}

/*打开协议*/
opendUserProtocol() {}

getNextBtn() {
final size = MediaQuery.of(context).size;
return TextButton(
onPressed: _onPressed(""),
child: const Text("下一步"),
autofocus: true,
/*style: TextButton.styleFrom(
//定义文本样式 这里设置的颜色是不起作用的
textStyle: const TextStyle(fontSize: 19,color: Colors.white),
padding: const EdgeInsets.all(15),
backgroundColor: const Color.fromRGBO(153, 153, 153, 0.3)
),*/
style: ButtonStyle(
//定义文本样式 这里设置的颜色是不起作用的
textStyle: MaterialStateProperty.all(
const TextStyle(
fontSize: 19, color: Color.fromRGBO(153, 153, 153, 0.3)),
),
//设置按钮字体颜色
foregroundColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.focused) &&
!states.contains(MaterialState.pressed)) {
//获取焦点时的颜色
return Colors.blue;
} else if (states.contains(MaterialState.pressed)) {
return Colors.red;
} else {
return Colors.white;
}
}),
//按钮的背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) {
const btnBGColor = Color.fromRGBO(153, 153, 153, 0.3);
if (states.contains(MaterialState.pressed)) {
return btnBGColor;
} else {
return btnBGColor;
}
}),
//padding: MaterialStateProperty.all(EdgeInsets.fromLTRB(15, 0, 15, 0)),
//设置按钮大小
minimumSize: MaterialStateProperty.all(Size(size.width, 52)),
//设置水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.purple)));
}

/*按钮事件*/
_onPressed(states) {
print("点击了按钮");
}
}

/*单元格*/
class BoxCellContainer extends StatelessWidget {
final String placeholder;
final String iconName;
final int index;

const BoxCellContainer(this.placeholder, this.iconName, this.index,
{Key? key})
: super(key: key);

@override
Widget build(BuildContext context) {
return SizedBox(
height: 75,
child: Column(children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
width: 20,
height: 20,
image: AssetImage(iconName),
fit: BoxFit.contain),
Expanded(
child: CupertinoTextField(
padding: const EdgeInsets.only(left: 15, right: 40),
placeholder: placeholder,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2.0),
border: Border.all(
color: const Color.fromRGBO(0, 0, 0, 0),
style: BorderStyle.solid,
width: 2.0)),
),
),
if (index == 0)
Image(
width: 20,
height: 20,
image: AssetImage(Toast2.loadImage("btn_inputbox_scan_nor")),
fit: BoxFit.cover),
//获取验证码
if (index == 2)
FlatButton(
child: const Text("获取验证码"),
color: const Color.fromRGBO(153, 153, 153, 0.3),
textColor: Colors.white,
onPressed: () {})
],
),
const Divider(
height: 10,
//分割线区域的高度,并非分割线的高度
thickness: 0.8,
//分割线的厚度,真正的分割线的高度
color: Color.fromRGBO(153, 153, 153, 0.3),
//分割线颜色
indent: 0,
//起点缩进距离
endIndent: 0) //终点缩进距离
]),
);
}
}