Flutter从入门到实战
一共分为23个系列
①(Flutter、Dart环境搭建篇) 共3个内容 已更新
②(Dart语法1 篇) 共4个内容 已更新
[③(Dart语法2 篇) 待更新 预计2022年03月13 更新]
④(Flutter案例开发篇) 共4个内容 已更新
⑤(Flutter的StatelessWidget 共3个内容 已更新
⑥(Flutter的基础Widget篇) 共2个内容 已更新
[⑦(布局Widget篇) 待更新 预计2022年03月13 更新]
参考文档
Dart官网
Dart中文官网我这边学习Dart语言 使用VSCode
VSCode的插件推荐 :
必须安装
《Dart、Flutter》插件、
Code Runner不需要直接点击运行 直接使用右键的Run Code即可以运行项目
main函数是dart入口
/**
* 1.main函数是dart入口
* 2.dart 当中 打印信息是引用 print函数
* */
main(List<String> args) {
// List args -> 列表 - 泛型
print("hello world");
}
String name = "宇夜iOS";
int age = 30;
类型推导虽然没有明确的额指定变量的类型,但是变量是有自己的明确的类型
- 使用
var
来声明变量- 使用
final
声明变量- 使用
const
声明变量final
和const
的区别 :
const
必须赋值常量
值(编译期间需要一个确定的值)
final
可以通过计算/函数
取得一个值
(运行期间来确定一个值)
var height = 171;
// 声明一个日期
final date2 = DateTime.now();
const p = Person("lyh"); // 声明一个人类的对象
const p2 = Person("lyh"); // 声明一个人类的对象
// const 声明的变量 使用 const的构造函数创建 两个对象相等
// 声明一个类
class Person {
final String name;
const Person(this.name);
}
main(List<String> args) {
var flag = true;
if (flag) {
print("执行代码");
}
}
'xxx'
var str1 = 'abc';
"xxx"
var str2 = "abc";
"""xxx"""
var str3 = """abc
cba
nba
""";
${变量}
// 字符串和表达式进行拼接
var name = "yh";
var age = "30";
var height = "171";
var msg = "my name ${name}, age is ${age}, height is ${height}";
var msg2 = " name is ${name}, type is ${name.runtimeType}";
print(msg);
print(msg2);
List
[v1,v2,v3]
var names = ["ios", "andorid", "rn", "flutter","ios"];
names.add("python"); // 添加
// names.remove(value); // 删除指定某个值
// names.removeAt(index); // 删除指定索引
Set
{vlaue1,vlaue2}
里面的数据不能重复
集合使用最多的就是 去重元素
var movies = {"开国典礼", "李小龙传奇", "逃学威龙"};
// from 是命名构造函数 传递一个可迭代的参数 返回的是Set 我们需要转换为List 可以通过 toList
// 去重
names = Set<String>.from(names).toList();
print(names); // ios,andorid,rn,flutter,python
{"key":vlaue}
var info = {"name": "lyh", "age": 17};
函数 注意点:
- 返回值的类型是可以省略(开发中不建议)
main(List<String> args) {}
// 返回值的类型是可以省略(开发中不建议)
int sum(int num1, int num2) {
return num1 + num2;
}
可选参数分为2个 位置可选参数、命名可选参数
void sayHello(String name) {
print(name);
}
可选参数的类型作用
- 位置可选参数
传不传都无所谓,但是参数的位置时对应的
实参
和实参
在进行匹配时,是根据位置
的匹配- 命名可选参数
开发经常见到这种写法
名字必须写
顺序随便
写
[]
sayHello2("yh");
// sayHello2("yh", 19, 20.2);
// 其中 name 是必传参数 age和height是可选参数的位置可选参数。 传不传都无所谓
void sayHello2(String name, [int age = 0, double height = 0.0]) {
print(" name ${name} age ${age} height ${height}");
}
{}
(开发经常常见)// 命名可选参数 名字必须写 顺序随便写
sayHello3("yh", age: 19);
sayHello3("yh", height: 171);
sayHello3("yh", height: 171,age: 30); // 顺序随便写
// 其中 name 是必传参数
void sayHello3(String name, {int age = 0, double height = 0.0}) {
print(" name ${name} age ${age} height ${height}");
}
什么是一等公民 可以理解为最重要
test(bar); // 执行bar函数
void test(Function foo) {
foo();
}
void bar() {
print("bar函数被调用");
}
匿名函数的格式
匿名函数 (参数列表) {函数体}
test(() {
print("匿名函数被调用");
return 100;
});
void test(Function foo) {
var result = foo();
print(result); // 100
}
箭头函数: 条件,
函数体
只有一行
代码
test(() => print("箭头函数被调用"));
void test(Function foo) {
foo();
}
带参数
)带参数
)可以作为另外一个函数的参数 test((num1, num2) {
return num1 + num2;
});
// int foo(int num1, int num2) 是一个函数表达式
void test(int foo(int num1, int num2)) {
int result = foo(20, 30);
print(result);
}
typedef
进行一个别名
为什么要使用typedef
因为 int foo(int num1, int num2) 名字太长了
typedef 在这里给函数进行起一个别名 。比如是一个计算的函数
typedef Calculate = int Function(int num1, int num2);
test((num1, num2) {
return num1 + num2;
});
typedef Calculate = int Function(int num1, int num2);
void test(Calculate calc) {
int result = calc(20, 30);
print(result);
}
// demo1 = 是一个返回值为 Calculate定义函数的别名的函数 的变量
// demo1 将20 和 30 代入到 demo里面
var demo1 = demo();
print(demo1(20, 30)); // 20 * 30 = 600
Calculate demo() {
// 匿名函数 执行了 num1 * num2
return (num1, num2) {
return num1 * num2;
};
}
??=的作用
- 当原来的变量有值时,name ??= 不执行
- 原来的变量为 null,那么将值赋值给这个变量
// ??= : 当原来的变量有值时,name ??= 不执行
// 原来的变量为 null,那么将值赋值给这个变量
// var name = null;
var name = "lyh";
name ??= "lysddd";
print(name);
// 1、 name = lyh 输出 lyh
// 2、name = null 输出 lysddd
?? 的作用
- ??前面的变量有值,那么就用??前面的变量
- ?? 前面的数据为 null,那么就使用后面的值
// ??前面的变量有值,那么就用??前面的变量
// ?? 前面的数据为 null,那么就使用后面的值
// 将name1 赋值给别人
var name1 = null;
// name1 = "gg";
var temp = name1 ?? "lysddd";
print(temp);
// 1.name1 = null 输出 lysddd
// 2. name = gg 输出 gg
// 普通调用函数
var p = Person();
p.name = "lyh";
p.run();
p.eat();
// 级联运算符调用
var p1 = Person()
..name = "yh"
..eat()
..run();
// 一行代码执行
var p1 = Person()..name = "yh"..eat()..run();
// 声明一个类
class Person {
String name = "";
void run() {
print("runiing");
}
void eat() {
print("eatiing");
}
}
for (var i = 0; i < 10; i++) {
print(i);
}
var names = ["yh", "cba", "nba"];
for (var i = 0; i < names.length; i++) {
print(names[i]);
}
var names = ["yh", "cba", "nba"];
for (var name in names) {
print(name);
}
// var p = Person(); 如果有构造函数 默认的构造函数会被覆盖掉 。这里就会报错
// 使用类的构造函数 快速创建一个类的对象
var p = Person("yh", 17);
class Person {
String name = "";
int age = 18;
// 定义一个构造函数 覆盖了系统默认的构造函数
// Person(String name, int age) {
// this.name = name;
// this.age = age;
// }
// 语法糖 等价于上面的函数
Person(this.name, this.age);
}
因为类没有重载,不能编写两个构造函数,延伸出来一个命名构造函数
类没有重载 所以不能同时编写构造两个函数
// 命名构造函数调用
var p = Person.withNameAgeHeight("yh", 19, 2.2);
// fromMap调用
var p2 = Person.fromMap({"name": "lyh", "age": 19, "height": 1.88});
print(p2); // 可以重写tostring方法 打印类的属性信息
class Person {
String name = "";
int age = 18;
double height = 1.88;
// 不能同时编写两个构造函数 因为类没有重载。 只能使用命名构造函数来完成这个操作
// Person(this.name, this.age);
// Person(this.name, this.age,this.height);
// 命名构造函数
Person.withNameAgeHeight(this.name, this.age, this.height);
// dynamic 任意类型
Person.fromMap(Map<String, dynamic> map) {
this.name = map["name"];
this.age = map["age"];
this.height = map["height"];
}
}
// 重载tostrong方法
@override
String toString() {
// TODO: implement toString
return "$name $age $height";
}
Object 调用方法时,编译器会报错
Object obj = "yh";
print(obj.substring(1)); // 会报错
dynamic 调用方法时,编译不报错,但是运行时存在安全隐患
dynamic obj1 = "yh";
print(obj1.substring(1));
var p = Person("yh", age: 10);
print(p.age);
const temp = 20;
class Person {
final String name;
final int age;
// 初始化列表 可以给初始化值
Person(this.name, {required int age}) : this.age = temp > 20 ? 30 : 50 {
}