在《Flutter 开发速成(一)——Flutter 环境搭建,创建第一个 Flutter 应用》中我们已经搭建完 Flutter 开发所需的环境,也运行了第一个 Flutter 程序。
俗话说,磨刀不误砍柴工,接下来我们要开始磨刀工作了,就是掌握 Flutter 和 Dart 的基础知识。
Flutter 是一个开发框架,Dart 是其开发语言,我们先从 Dart 入手。当然,有 Dart 基础的开发人员可直接跳过 Dart 基础学习这一步,学习 Flutter 框架。
Dart 基础
Dart 学习
学习资料:Dart 官网(dart.dev/language#va…)
开发工具:vscode(需要安装 Dart 插件)
快速入门不需要深入学习 Dart,我们只需要掌握基础就行,后续可根据需求及自身喜好进行深入。
对于完全没有基础的,建议学习下图红框中的内容。对于纯 web 前端开发 Dart 与 JS 有许多相似,如果还有 Java 或者 C#这些编程语言基础,学习 Dart 可以说是非常的轻松了。
Dart 基础知识总结
下面总结了一些 Dart 的基础知识帮助快速入门。
Hello Dart
每个 Dart 应用程序都需要一个main()函数作为入口。mian()函数没有显式返回值,其返回类型写 void 或者不写。使用print()函数在控制台上打印文本。main()函数和 print 函数都是 Dart 的基础函数。
void main() {
print('Hello, World!');
}
基础语法
变量
Dart 的变量会推断其数据类型。如果将一个已经确认数据类型的变量修改为其他类型,程序会报错
显示声明变量
var str = 'hello';
print(str);
// str = 12; 会报错:因为定义中已经推断str是字符串类型
// 字符串类型变量
String str1 = 'hi';
print(str1);
// 数字类型变量
int myNum = 12;
print(myNum);
隐式声明变量:var 声明变量 Dart 会自动推算数据类型
var name = 'Bob';
// name=1;会报错:因为定义中已经推断name是字符串类型
常量
Dart 常量使用 final 和 const 修饰符
const 值不变,一开始就得赋值 final 可以开始不赋值,只能赋值一次;final 不仅有 const 的特性,最重要的是它是运行时的常量,并且 final 是惰性初始化,在运行时第一次使用才初始化
// const定义常量
const PI = 3.1435;
print(PI);
// PI=1333; 会报错
// final定义常量
final PI1 = 3.144;
print(PI1);
final a = new DateTime.now();
print(a);
// const a=new DateTime.now();错误
操作符
对比 js 的常用操作符:常用的与 js 的操作符差不多,特别的:??(是否为空),~/(取整)
int a = 3;
a ??= 24; //a=3 如果a为空,把23赋值给a
int b=8/3; //b=2
注释
对比 js 注释符:多一个注释符 ///,这个用法和// 一样,都是单行注释
单行注释://、///
多行注释:/* */
条件表达式
1、基础的 if-else switch-case 和其他语言一样
2、三目运算符
bool flag = true;
var data = flag ? '1' : '0';
print(data);
3、??:空判断运算符
var a;
var b = a ?? 10;
print(b);
数据类型
Numbers (int, double):数值
int 必须是整形;double 可以是整形也可以是浮点型
int a = 1;
print(a);
double b = 1.2;
b = 12;
print(b);
Strings (String):字符串
1、定义字符串类型的几种方式
//1、var + 单引号
var str1 = '这是str1';
2、var + 双引号
var str2 = "这是str2";
print(str1);
print(str2);
//3、String +单引号
String str3 = '这是str3';
print(str3);
//4、String +三引号
String str4 = '''hello
你好 str4
''';
print(str4);
String str5 = """
hello
你好
str5
""";
print(str5);
2、字符串的拼接
String str1 = '这是str1';
String str2 = "这是str2";
print('$str1 $str2');
print(str1 + str2);
Booleans (bool):布尔
bool 值 true 或者 false
bool flag1 = true;
print(flag1);
Lists:数组,在 Dart 中,数组是列表对象,所以也叫列表
1、第一种定义 List 方式
var l1 = ['张三', 20, true];
print(l1);
print(l1.length);
print(l1[0]);
2、第二种定义 List 方式 指定类型
var l2 = <String>['hahhaha', '张三']; //指定列表元素类型必须是String类型
print(l2);
var l3 = <int>[12, 13]; //指定列表元素类型必须是int类型
print(l3);
3、第 3 种定义 List 方式 增加数据。通过[]创建的 List 长度是可变的
var l4 = []; //长度可变
print(l4);
print(l4.length); //0
l4.add(3);
l4.add('张三');
print(l4);
print(l4.length); //2
4、创建一个固定长度集合,无法增加数据,也无法修改其长度
var l6 = List.filled(2, ''); //创建一个固定长度集合,无法增加数据,也无法修改其长度
print(l6);
print(l6[0]);
5、修改数据
list[0] = '张三';
6、改变[]创建的集合的长度
var l7 = ['张三', '李四']; //长度可变
print(l7.length);
l7.length = 0;
print(l7.length);
Maps (Map):字典。Map 是相关键值对相关的对象
Dart 的 Map 类似于 js 的对象,但是无法通过. 操作符访问字典中的数据,需要通过mapData[<字典中的键>] 访问
1、第一种定义 map 方法
var person = {"name": "张三", "age": 20};
print(person);
print(person['name']);
print(person['age']);
2、第 2 种定义 map 方法
var p = new Map();
p['name'] = '李四';
p['age'] = 20;
print(p);
数据类型判断
is 关键词判断数据类型
var str = '1243';
if (str is String) {
print('String类型');
} else {
print('其他');
}
控制台输出:String 类型
Sets
Set 是没有顺序且不能重复的集合,所以不能通过索引取值
Set 的主要功能就是对数组进行去重
var s = new Set();
s.add('香蕉');
s.addAll(['苹果', '香蕉']);
print(s);
print(s.toList());
数据类型转换
1、Number 与 String 类型之间的转换:
Number->String:toString()
String->Number:int.parse()或者 double.parse()
String a = '123';
var myNum = int.parse(a);
print(myNum is int);
var myStr = myNum.toString();
print(myStr is String);
2、其他类型转换为 Booleans
字符串类型转换为布尔类型:isEmpty
var str = '';
if (str.isEmpty) {
print('不为空');
}
数值转换为布尔类型:isNaN
var myNum = 123;
if (myNum.isNaN) {
print('不是数值');
} else {
print('是数值');
}
集合
List 常用属性和方法
属性:
- length:长度
- reversed:翻转
- isEmpty:是否为空
- isNotEmpty:是否不为空
方法:
- add 增加
- addAll 拼接数组
- indexOf 查找 传入具体值
- remove 删除 传入具体值
- removeAt 删除 传入索引值
- fillRange 修改
- insert(index,value) 指定位置插入
- insertAll(index,list) 指定位置插入 List
- toList 其他类型转换为 List
- join list 转换为字符串
- split 字符串转换为 list
- 循环:
- forEach
- map
- where
- any
- every
Map 常用属性和方法
映射(Maps)是无序的键值对
常用属性:
- keys
- values
- isEmpty
- isNotEmpty
常用方法
- remove(key)
- addAll({})
- containerValue 查看映射内的值 返回 true/false
- forEach
- map
- where 相当于 js 的 filter
- any 返回 true/false
- every 返回 true/false
循环语句
Dart 的循环语法和我们常用的 js、java、c 语言等是一样的
1、for 循环
for (int i = 1; i < 5; i++) {
print(i);
}
2、while 循环
while(条件/表达式){
}
3、do-while 循环
do{
}while(条件/表达式);
函数
定义一个函数
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
箭头函数:箭头函数中只能写一句话
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
匿名函数
var myFunc = (n) {
print(n);
};
自执行函数
((n) {
print('执行自执行方法');
print(n);
})(11);
闭包
函数嵌套函数,并且返回一个函数,不会污染内存
void main() {
fn() {
var a = 12; //不会污染全局,常驻变量
return () {
a++;
print(a);
};
}
var b = fn();
b();
b();
b();
}
面向对象
Dart 是一种面向对象的语言。面向对象编程中的三大要素是:封装、继承和多态。
- 封装:封装是指将对象的属性和方法集合在一起,对外部隐藏对象的实现细节,只暴露必要的接口供外部访问。这样可以保护对象的内部状态不被外界随意修改,提高了代码的安全性和可维护性。
- 继承:继承是指子类可以继承父类的属性和方法,并可以在此基础上扩展自己的特有属性和方法。通过继承,可以减少代码的冗余和重复,提高了代码的复用性。
- 多态:多态是指同一种类型的对象,在不同的情况下可以表现出不同的行为。多态实现了代码的灵活性和可扩展性,使得程序可以更加适应变化和扩展。
类成员
对象由方法和数据组成。
类中的变量我们成为成员数据,类中的函数我们称为成员方法。
dart 中创建类和使用类
使用 class 修饰符创建类,类的定义首字母必须大写(大驼峰)。
类中有个默认构造函数,默认构造函数与类同名,在实例化一个类的时候,默认构造函数会自动执行,在这个函数中我们可以做属性的初始化。
下方代码的 main()方法中Person p1 = new Person('李四', 13); ,p1 是一个 Person 类的实例,可以通过.操作符访问其属性和方法。
// 类的定义首字母必须大写(大驼峰),函数的定义首字母小写
class Person {
String name = '张三';
int age = 12;
// 默认构造函数
Person(name, age) {
print('执行构造函数2');
this.name = name;
this.age = age;
}
printInfo() {
print("${this.name}-----${this.age}");
}
}
void main() {
Person p1 = new Person('李四', 13);
p1.printInfo();
}
继承
使用extends创建子类,并super引用父类。
下方代码:Student 类继承自 Person 类,Student 是 Person 的父类,Person 是 Student 的子类。子类会继承父类暴露的成员方法和成员数据,在子类的实例中也就可以访问这些暴露的成员方法和成员数据。
class Person {
String name = '张三';
int age = 12;
Person(name, age) {
this.name = name;
this.age = age;
}
printInfo() {
print("${this.name}-----${this.age}");
}
}
class Student extends Person {
Student(super.name, super.age);
}
void main() {
var s1 = new Student('李四', 22);
s1.printInfo();
}
上边是类的基本使用,是必须要掌握的。Dart 面向对象的更多知识可根据 Dart 官网进行学习。
Flutter 基础
Flutter 学习
学习资料:
- Flutter 官网(docs.flutter.dev/ui)
- 《Flutter 实战·第二版》
开发工具:vscode(需要安装 flutter 插件)
其他准备:使用命令行工具或者 AS 构建一个 Flutter 应用。
学习步骤:
-
了解 Flutter 的 widgets
基本的 Flutter 开发就是使用 Flutter 提供的小组件(widgets)构建用户界面,初学者建议通读 Flutter 官方的 widgets 的使用和介绍文档(docs.flutter.dev/ui#handling…)。
-
理解构建的 Flutter 项目默认生成的计数器 demo
在 Flutter 实战·第二版中有完整的模板代码分析,帮助理解代码。(book.flutterchina.club/chapter2/fi…)
-
修改代码,使用常用的小组件,了解它们的构造函数中常用的属性和方法
-
自定义一个小组件
Flutter 基础知识总结
下面总结了一些 Flutter 的基础知识帮助快速入门。
MaterialApp 和 Scaffold
使用 MaterialApp 和 Scaffold 两个组件装饰 App
1、MaterialApp MaterialApp 是一个方便的 Widget,它封装了应用程序实现 Material Design 所需要的一些 Widget。一般作为顶层 widget 使用。 常用的属性:
- home(主页)
- title(标题)
- color(颜色)
- theme (主题)
- routes(路由) ...
2.Scaffold Scaffold 是 Material Design 布局结构的基本实现。此类提供了用于显示 drawer、snackbar 和底部 sheet 的 API。 scaffold 有下面几个主要属性:
- appBar-显示在界面顶部的一个
- body -当前界面所显示的主要内容
- Widget.drawer-抽屉菜单控件。
void main() {
// 1、简单的内容
// runApp(const Center(
// child: Text(
// "Hello",
// textDirection: TextDirection.ltr,
// style: TextStyle(
// color: Colors.red,
// // color: Color.fromRGBO(244, 244, 244, 1),
// fontSize: 40,
// ),
// ),
// ));
// 2、使用组件修饰App
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("你好")),
body: const Center(
child: Text(
"Hello",
textDirection: TextDirection.ltr,
style: TextStyle(
color: Colors.red,
// color: Color.fromRGBO(244, 244, 244, 1),
fontSize: 40,
),
),
),
)));
}
有状态组件和无状态组件(StatelessWidget/StatefulWidget)
在 Flutter 中自定义组件其实就是一个类,这个类需要继承 StatelessWidget/StatefulWidget
- StatelessWidget 是无状态组件,状态不可变的 widget
class name extends StatelessWidget {
const name({super.key});
@override
Widget build(BuildContext context) {
return Container();
}
}
- StatefulWidget 是有状态组件,持有的状态可能在 widget 生命周期改变。
我们自定义的一个组件如果需要做响应式,那么久需要继承 StatefulWidget,这样它的变化数据才会更新到视图。
class name extends StatefulWidget {
const name({super.key});
@override
State<name> createState() => _nameState();
}
class _nameState extends State<name> {
@override
Widget build(BuildContext context) {
return Container();
}
}
常用基础 Widget
该Text小部件允许您在应用程序中创建一系列样式文本。
这些 Flex 小部件可让您在水平 ( Row) 和垂直 ( Column) 方向上创建灵活的布局。这些对象的设计基于 Web 的 Flexbox 布局模型。
小部件不是线性定向(水平或垂直),而是Stack允许您按绘制顺序将小部件放置在彼此的顶部。Positioned然后,您可以在 a 的子级上 使用小部件Stack,将它们相对于堆栈的顶部、右侧、底部或左侧边缘进行定位。堆栈基于网络的绝对定位布局模型。
该Container小部件允许您创建矩形视觉元素。容器可以用 装饰BoxDecoration,例如背景、边框或阴影。AContainer还可以具有对其大小应用的边距、填充和约束。另外,a Container可以使用矩阵在三维空间中进行变换。
ListView是最常用的可滚动组件之一,它可以沿一个方向线性排布所有子组件,并且它也支持列表项懒加载(在需要时才会创建)。
补充:组件查询
- 1、Ctrl+鼠标左键查看组件源码,根据源码的注释了解对应组件的构造函数;
- 2、在《Flutter 实战.第二版》中查看组件的使用:book.flutterchina.club/#%E7%AC%AC%… ;
- 3、官网文档查询组件构造函数和参数:api.flutter-io.cn/flutter/wid…
跨组件的状态管理:
在前端开发中,状态管理是重要的功能块,像 Vue 中的 Vux,或者是 React 的 Redux,给开发人员提供了非常大的便利。
InheritedWidget
InheritedWidget 是 Flutter 中非常重要和强大的一种 Widget,它可以使 Widget 树中的祖先 Widget 共享数据给它们的后代 Widget,从而简化了状态管理和数据传递的复杂性,提高了代码的可读性、可维护性和性能。
短篇幅的文字无法解释清 InheritedWidget 的使用 ,直接阅读《Flutter 实战.第二版》了解 InheritedWidget:book.flutterchina.club/chapter7/in…
Pvovider
Provider 是 Flutter 官方出的状态管理包,就是对 inheritedWidget 的高度封装。
Pvovider 的使用:github.com/rrousselGit…
其他一些 Flutter 的状态管理包:book.flutterchina.club/chapter7/pr…