Flutter 开发速成(二)——Dart、Flutter 基础

578 阅读12分钟

在《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 可以说是非常的轻松了。

image.png

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

image.png

注释

对比 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 是一种面向对象的语言。面向对象编程中的三大要素是:封装、继承和多态。

  1. 封装:封装是指将对象的属性和方法集合在一起,对外部隐藏对象的实现细节,只暴露必要的接口供外部访问。这样可以保护对象的内部状态不被外界随意修改,提高了代码的安全性和可维护性。
  2. 继承:继承是指子类可以继承父类的属性和方法,并可以在此基础上扩展自己的特有属性和方法。通过继承,可以减少代码的冗余和重复,提高了代码的复用性。
  3. 多态:多态是指同一种类型的对象,在不同的情况下可以表现出不同的行为。多态实现了代码的灵活性和可扩展性,使得程序可以更加适应变化和扩展。
类成员

对象由方法和数据组成。

类中的变量我们成为成员数据,类中的函数我们称为成员方法。

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 学习

学习资料:

开发工具:vscode(需要安装 flutter 插件)

其他准备:使用命令行工具或者 AS 构建一个 Flutter 应用。

学习步骤:

  1. 了解 Flutter 的 widgets

    基本的 Flutter 开发就是使用 Flutter 提供的小组件(widgets)构建用户界面,初学者建议通读 Flutter 官方的 widgets 的使用和介绍文档(docs.flutter.dev/ui#handling…)。

  2. 理解构建的 Flutter 项目默认生成的计数器 demo

    在 Flutter 实战·第二版中有完整的模板代码分析,帮助理解代码。(book.flutterchina.club/chapter2/fi…

  3. 修改代码,使用常用的小组件,了解它们的构造函数中常用的属性和方法

  4. 自定义一个小组件

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

Text小部件允许您在应用程序中创建一系列样式文本。

Row,Column

这些 Flex 小部件可让您在水平 ( Row) 和垂直 ( Column) 方向上创建灵活的布局。这些对象的设计基于 Web 的 Flexbox 布局模型。

Stack

小部件不是线性定向(水平或垂直),而是Stack允许您按绘制顺序将小部件放置在彼此的顶部。Positioned然后,您可以在 a 的子级上 使用小部件Stack,将它们相对于堆栈的顶部、右侧、底部或左侧边缘进行定位。堆栈基于网络的绝对定位布局模型。

Container

Container小部件允许您创建矩形视觉元素。容器可以用 装饰BoxDecoration,例如背景、边框或阴影。AContainer还可以具有对其大小应用的边距、填充和约束。另外,a Container可以使用矩阵在三维空间中进行变换。

ListView*

ListView是最常用的可滚动组件之一,它可以沿一个方向线性排布所有子组件,并且它也支持列表项懒加载(在需要时才会创建)。

补充:组件查询

跨组件的状态管理:

在前端开发中,状态管理是重要的功能块,像 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…