Flutter(知识点小结)

学习网址
https://book.flutterchina.club/
运算符

main() { // 与Java相同的运算符操作int a = 1; ++a; a++; var b = 1; print(a == b); // false print(a * b); // 3 bool real = false; real ? print('real') : print('not real'); // not real print(real && a == b); // false print(real || a == 3); // true print(a != 2); // true print(a <= b); // false var c = 9; c += 10; print("c = $c"); // c = 19 print(1<<2); // 4============================================// 与Java不太一样的运算符操作 // is 运算符用于判断一个变量是不是某个类型的数据 // is! 则是判断变量不是某个类型的数据 var s = "hello"; print(s is String); // true var num = 6; print(num is! String); // true// `~/` 才是取整运算符,如果使用 `/` 则是除法运算,不取整 int k = 1; int j = 2; print(k / j); // 0.5 print(k ~/ j); // 0// `as` 运算符类似于Java中的cast操作,将一个对象强制类型转换 (emp as Person).teach(); // ??=运算符 如果 ??= 运算符前面的变量为null,则赋值,否则不赋值 var param1 = "hello", param2 = null; param1 ??= "world"; param2 ??= "world"; print("param1 = $param1"); // param1 = hello print("param2 = $param2"); // param2 = world// ?.运算符 var str1 = "hello world"; var str2 = null; print(str1?.length); // 11 print(str2?.length); // null print(str2.length); // 报错 }

Dart 没有 public protected private 等关键字,如果某个变量以下划线_开头,代表这个变量在库中是私有的。
Dart之可选命名参数和可选位置参数
// 可选命名参数:在方法参数中,使用"{}"包围的参数属于可选命名参数 void _testName(String name, {int age = 18, String email}) {}// 调用包含可选命名参数的方法时,需要使用 `paramName:value`的形式指定为哪个可选参数赋值 _testName('Name', age: 18); ----// 可选位置参数:在方法参数中,使用"[]"包围的参数属于可选位置参数 void _testLocation(String name, [int age = 20, String email]) {}// 可选位置参数是位置,如果想指定某个位置上的参数值,则必须前面位置的已经有值,即使前面的值存在默认值。 _testLocation('Location', 17, '98');

GlobalKey:用于跨 widget 调用。

Flutter(知识点小结)
文章图片

示例:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: MyHomePage(), ); } }class MyHomePage extends StatefulWidget { MyHomePage({Key key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); }class _MyHomePageState extends State { final GlobalKey key = GlobalKey(); @override Widget build(BuildContext context) { return Scaffold( body: SwitcherWidget( key: key, ), floatingActionButton: FloatingActionButton( onPressed: () { key.currentState.changeState(); }, child: Text('切换'), ), ); } }class SwitcherWidget extends StatefulWidget { SwitcherWidget({Key key}) : super(key: key); @override SwitcherWidgetState createState() => SwitcherWidgetState(); }class SwitcherWidgetState extends State { bool isActive = false; @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Switch.adaptive( value: isActive, activeColor: Colors.blueAccent, onChanged: (bool currentStatus) { isActive = currentStatus; setState(() {}); }), ), ); }changeState() { isActive = !isActive; setState(() {}); } }

RaisedButton 的 shape 是抽象的 ShapeBorder 类型。
统一四边颜色和宽度 shape: Border.all(color: Color(0xFF00FFFF),style: BorderStyle.solid,width: 2) // 四个边分别指定颜色和宽度, 当只给bottom时与UnderlineInputBorder一致效果 //shape: Border(top: b, bottom: b, right: b, left: b) // 底部线 //shape: UnderlineInputBorder( borderSide:BorderSide(color: Color(0xFFFFFFFF), style: BorderStyle.solid, width: 2)) // 矩形边色 //shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10)), side: BorderSide(color: Color(0xFFFFFFFF), style: BorderStyle.solid, width: 2)) // 圆形边色 //shape: CircleBorder(side: BorderSide(color: Color(0xFFFFFF00), style: BorderStyle.solid, width: 2)) // 体育场(竖向椭圆) //shape: StadiumBorder(side: BorderSide(width: 2, style: BorderStyle.solid, color: Color(0xFF00FFFF)) // 角形(八边角)边色 //shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10)), side: BorderSide(color: Color(0xFFFFFFFF), style: BorderStyle.solid, width: 2))

类型检查操作符
as:类型转换
is:对象是定义类型则返回 true,当对象是定义类型的子类或者实现类时,也返回 true
is!:对象是定义类型则返回 false
as 操作符可以将对象类型判断和使用两个行为进行合并,如下:
//is 方式 if (emp is Person) { // Type check emp.firstName = 'Bob'; }//as 方式,注意当 emp 为 null 或者不是 Person类型时,会抛出异常 (emp as Person).firstName = 'Bob';

赋值操作符
??= 表示当左边变量为 null 时,将右边的值赋给左边变量。
b ??= value;

条件操作符
condition ? expr1 : expr2 :满足条件返回 expre1,否则返回expre2
expr1 ?? expr2:``expre1 不为null时返回 expre1,否则返回 expre2
var visibility = isPublic ? 'public' : 'private'; String playerName(String name) => name ?? 'Guest';

级联操作符(..)
使用 .. 操作符可以对同一对象执行一系列操作,能够节省中间步骤和临时变量,让代码更高效。
其实严格来说, .. 级联语法不是一个操作符。 只是一个 Dart 特殊语法。
querySelector('#confirm') // Get an object. ..text = 'Confirm' // Use its members. ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed!'));

enum MainAxisAlignment { start,//将子控件放在主轴的开始位置 end,//将子控件放在主轴的结束位置 center,//将子控件放在主轴的中间位置 spaceBetween,//将主轴空白位置进行均分,排列子元素,首尾没有空隙 spaceAround,//将主轴空白区域均分,使中间各个子控件间距相等,首尾子控件间距为中间子控件间距的一半 spaceEvenly,//将主轴空白区域均分,使各个子控件间距相等 }

final和const的区别:
区别一:final 要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而 const 要求在声明时初始化,并且赋值必需为编译时常量。
区别二:final 是惰性初始化,即在运行时第一次使用前才初始化。而 const 是在编译时就确定值了。
类的定义与构造方法
Dart中的类没有访问控制,所以你不需要用private, protected, public等修饰成员变量或成员函数。
class Person { String name; int age; String gender; Person(this.name, this.age, this.gender); sayHello() { print("hello, this is $name, I am $age years old, I am a $gender"); } }

上面的Person类中有3个成员变量,一个构造方法和一个成员方法,看起来比较奇怪的是Person的构造方法,里面传入的3个参数都是this.xxx,而且没有大括号{}包裹的方法体,这种语法是Dart比较独特而简洁的构造方法声明方式,它等同于下面的代码:
Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; }

要调用Person类的成员变量或成员方法,可以用下面的代码:
var p = new Person("zhangsan", 20, "male"); p.sayHello(); // hello, this is zhangsan, I am 20 years old, I am a male p.age = 50; p.gender = "female"; p.sayHello(); // hello, this is zhangsan, I am 50 years old, I am a female

Dart中使用extends关键字做类的继承,如果一个类只有命名的构造方法,在继承时需要注意,如下代码:
class Human { String name; Human.fromJson(Map data) { print("Human's fromJson constructor"); } }class Man extends Human { Man.fromJson(Map data) : super.fromJson(data) { print("Man's fromJson constructor"); } }

由于Human类没有默认构造方法,只有一个命名构造方法fromJson,所以在Man类继承Human类时,需要调用父类的fromJson方法做初始化,而且必须使用Man.fromJson(Map data) : super.fromJson(data)这种写法,而不是像Java那样将super写到花括号中
有时候你仅仅只是在某个类的构造方法中,调用这个类的另一个构造方法,你可以这么写:
class Point { num x, y; Point(this.x, this.y); // 命名构造方法调用了默认的构造方法 Point.alongXAxis(num x) : this(x, 0); }

类的成员方法
一个类的成员方法是一个函数,为这个类提供某些行为。上面的代码中已经有了一些类的成员方法的定义,这些定义方式跟Java很类似,你可以为某个类的成员变量提供getter/setter方法,如下代码:
class Rectangle { num left, top, width, height; // 构造方法传入left, top, width, height几个参数 Rectangle(this.left, this.top, this.width, this.height); // right, bottom两个成员变量提供getter/setter方法 num get right => left + width; set right(num value) => left = value - width; num get bottom => top + height; set bottom(num value) => top = value - height; }

抽象类和抽象方法
使用abstract修饰一个类,则这个类是抽象类,抽象类中可以有抽象方法和非抽象方法,抽象方法没有方法体,需要子类去实现,如下代码:
abstract class Doer { // 抽象方法,没有方法体,需要子类去实现 void doSomething(); // 普通的方法 void greet() { print("hello world!"); } }class EffectiveDoer extends Doer { // 实现了父类的抽象方法 void doSomething() { print("I'm doing something..."); } }

运算符重载
Dart中有类似于C++中的运算符重载语法,比如下面的代码定义了一个向量类,重载了向量的+ -运算:
class Vector { num x, y; Vector(this.x, this.y); Vector operator +(Vector v) => new Vector(x + v.x, y + v.y); Vector operator -(Vector v) => new Vector(x - v.x, y - v.y); printVec() { print("x: $x, y: $y"); } }main() { Vector v1 = new Vector(1, 2); Vector v2 = new Vector(3, 4); (v1 - v2).printVec(); // -2, -2 (v1 + v2).printVec(); // 4, 6 }

枚举类
使用enum关键字定义一个枚举类,这个语法跟Java类似,如下代码:
enum Color { red, green, blue }

mixins
mixins是一个重复使用类中代码的方式,比如下面的代码:
class A { a() { print("A's a()"); } }class B { b() { print("B's b()"); } }// 使用with关键字,表示类C是由类A和类B混合而构成 class C = A with B; main() { C c = new C(); c.a(); // A's a() c.b(); // B's b() }

静态成员变量和静态成员方法
// 类的静态成员变量和静态成员方法 class Cons { static const name = "zhangsan"; static sayHello() { print("hello, this is ${Cons.name}"); } }main() { Cons.sayHello(); // hello, this is zhangsan print(Cons.name); // zhangsan }

静态成员变量和静态成员方法
// 类的静态成员变量和静态成员方法 class Cons { static const name = "zhangsan"; static sayHello() { print("hello, this is ${Cons.name}"); } }main() { Cons.sayHello(); // hello, this is zhangsan print(Cons.name); // zhangsan }

泛型(Generics)
Java和C++语言都有泛型,Dart语言也不例外,使用泛型有很多好处,比如:
正确指定泛型类型会产生更好的生成代码。
泛型可以减小代码的复杂度
Dart内置的数据类型List就是一个泛型数据类型,你可以往List中塞任何你想的数据类型比如整型、字符串、布尔值等
Dart库(Libraries)的导入
Dart目前已经有很多的库提供给开发者,许多功能不需要开发者自己去实现,只需要导入对应的包即可,使用import语句来导入某个包,比如下面的代码:
import 'dart:html';

如果你想导入自己写的某个代码文件,使用相对路径即可,例如当前有一个demo.dart文件,跟该文件同级目录下有个util.dart文件,文件代码如下:
// util.dart文件内容 int add(int a, int b) { return a + b; }

在demo.dart文件中如果要引用util.dart文件,使用下面的方式导入:
// demo.dart import './util.dart'; main() { print(add(1, 2)); }

【Flutter(知识点小结)】你可以使用as关键字为导入的某个包设置一个前缀,或者说别名,比如下面的代码:
import 'package:lib1/lib1.dart'; import 'package:lib2/lib2.dart' as lib2; // Uses Element from lib1. Element element1 = Element(); // Uses Element from lib2. lib2.Element element2 = lib2.Element();

你也可以在导入包时使用show / hide关键字来导入某个包中的部分功能,比如下面的代码:
// 只导入foo import 'package:lib1/lib1.dart' show foo; // 导入除了foo的所有其他部分 import 'package:lib2/lib2.dart' hide foo;

导入包时使用deferred as可以让这个包懒加载,懒加载的包只会在该包被使用时得到加载,而不是一开始就加载,比如下面的代码:
import 'package:greetings/hello.dart' deferred as hello;

异步
Dart提供了类似ES7中的async await等异步操作,这种异步操作在Flutter开发中会经常遇到,比如网络或其他IO操作,文件选择等都需要用到异步的知识。
asyncawait往往是成对出现的,如果一个方法中有耗时的操作,你需要将这个方法设置成async,并给其中的耗时操作加上await关键字,如果这个方法有返回值,你需要将返回值塞到Future中并返回,如下代码所示:
Future checkVersion() async { var version = await lookUpVersion(); // Do something with version }

下面的代码使用Dart从网络获取数据并打印出来:
import 'dart:async'; import 'package:http/http.dart' as http; Future getNetData() async{ http.Response res = await http.get("http://www.baidu.com"); return res.body; }main() { getNetData().then((str) { print(str); }); }

参考:
原汁原味的 Dart语言 官网

    推荐阅读