慕课网《Flutter从入门到进阶》学习笔记二

Flutter必备Dart基础:Dart快速入门

学习资料

Dart中文网


4-1 Flutter之Dart概述

Dart特性:
JIT:即时编译,开发期间,更快编译,更快重载。
AOT:事前编译,release期间,更快更流畅。


4-2 Flutter之Dart常用数据类型(数字、类型转换)

常用数据类型:
在这里插入图片描述
创建dart_type.dart

option + 回车引入头文件
option + 回车创建方法

int类型和double类型是num类型的子类。

常用API:

    num num1 = -1.0; // 是数字类型的父类
    num num2 = 2; // 是数字类型的父类
    int int1 = 3; // 只能是整数,int是num的子类
    double d1 = 1.68; // 双精度,double是num的子类
    print("num:$num1 num: $num2 int: $int1 double: $d1");

    print(num1.abs());  // 求绝对值
    print(num1.toInt());  // 转换成int类型
    print(num1.toDouble()); // 转换成double

4-3 Flutter之Dart常用数据类型(字符串)

Dart里面定义字符串可以用双引号也可以用单引号。
拼接字符串可以用+也可以用单引号$符号。
字符串其它方法:startsWith, replaceAll, contains, split等。

  // 字符串使用
  void _stringType() {
    String str1 = '字符串';
    String str2 = "双引号";
    String str3 = "str1:$str1 str2:$str2"; // 字符串拼接
    String str4 = 'str1: ' + str1 + 'str2: ' + str2; // 字符串拼接
    print(str3);
    print(str4);

    // 常用方法
    String str5 = '常用数据类型,请看控制台输出';
    // 截取字符串
    print(str5.substring(1, 5));  //输出:用数据类
    // 获取字符串在字符串中的位置
    print(str5.indexOf('类型'));   // 输出:4
    // 其它方法:startsWith, replaceAll, contains, split等
  }

Dart中方法都加下划线,同时要放在build方法中:

  Widget build(BuildContext context) {
    _numType(); // 方法放在build里面
    _stringType();  // 字符串方法
    return Container(
      child: Text('常用数据类型,请查看控制台输出'),
    );
  }

4-4 Flutter之Dart常用数据类型(布尔, List)

bool类型用法:

  // 布尔类型,Dart是强bool类型检查,只有bool类型的值是true,才被认为是true
  void _boolType() {
    bool success = true;
    bool fail = false;
    print(success);
    print(fail);

    // 常用方法
    print(success || fail); // 逻辑或
    print(success && fail); // 逻辑与
  }

集合List用法:

void _listType() {
    print('----_listType----');
    // 集合初始化的方式
    List list = [1, 2, 3, '集合']; // 1:初始化时添加元素
    print(list); // 输出:flutter: [1, 2, 3, 集合]
    List<int> list2 = []; // 集合只能是int类型
    // list2 = list; // 错误做法,类型转换错误
    List list3 = [];
    list3.add('list3');
    list3.addAll(list);
    print(list3); // 输出:flutter: [list3, 1, 2, 3, 集合]

    // 集合生成函数
    // 第1个参数是元素数量
    // 第2个参数是生成规则
    List list4 = List.generate(3, (index) => index * 2);
    print(list4); // 输出:flutter: [0, 2, 4]
  }

遍历List的3种方法:for循环, for...inforEach

    // 遍历集合的方式:for循环
    for (int i = 0; i < list.length; i++) {
      print(list[i]);
    }

    // 遍历集合的方式2
    for (var item in list) {
      print(item);
    }

    // 遍历集合的方式3:forEach
    list.forEach((element) {
      print(element);
    });

List其它方法:list.removeXx, insert, sublist, indexof


4-5 Flutter之Dart常用数据类型(Map)

map<key,value>结构,keyvalue可以是任何类型的对象,并且key是唯一的,如果key重复后面添加的value覆盖之前的value值。

Map初始化的2种方式:注意List初始化是[]Map{}

    // Map初始化方式1
    // key和value通过冒号分割,元素通过逗号分割
    // 集合List初始化是[], Map是{}
    Map names = {'xiaoming': '小明', 'xiaohong': '小红'}; 
    print(names);
    
    // Map初始化方式2
    Map ages = {};
    ages['xiaoming'] = 16;
    ages['xiaohong'] = 18;
    print(ages);

Map遍历的3种方式:forEachfor循环、map方法

  // Map遍历:forEach
    ages.forEach((key, value) {
      print('$key, $value');
    });

    // Map遍历:for循环
    for (var key in ages.keys) {
      print('$key ${ages[key]}'); //  注意是${ages[key]},${}
    }
    
    // Map遍历:使用map方法
    // map方法返回一个新的Map
    ages.map((key, value) {
      print('$key $value');
      return MapEntry(value, key);  // 颠倒key,value
    });
  

创建key,value颠倒的Map:使用MapEntry构造新Map,使用map方法。

    // 创建k,v颠倒的Map
    Map ages2 = ages.map((k, v) {
      return MapEntry(v, k);
    });
    print(ages2); // 打印颠倒k,v的Map

注意map方法返回的是1个新的Map
其它方法:keys, values, remove, containsKey


4-6 Flutter之Dart常用数据类型(科普小姿势)

dynamicvarObject三者的区别:

dynamic:是所有Dart对象的基础类型,在大多数情况下,通常不直接使用它

通过dynamic定义的变量会关闭类型检查,这意味着dyamic x = 'hal'; x.foo();这段代码静态类型检查不会报错,但是运行的时候会报错,因为x没有foo()方法,所以建议大家在编程时不要直接使用dynamic

dynamic可以定义任意的数据类型,但是会导致Dart语法检查失效
dynamic赋值的变量只有在运行时才知道数据类型

变量.runtimeType 输出变量的类型

    // dynamic动态数据类型
    // dynamic可以定义任意的数据类型,但是会导致Dart语法检查失效
    // dynamic赋值的变量只有在运行时才知道数据类型
    dynamic x = 'hal';
    print(x.runtimeType); // 输出:flutter: String
    print(x); // 输出:flutter: hal
    // x.foo(); // 编译不报错,运行报错

    x = 123;
    print(x.runtimeType); // 输出:flutter: int
    print(x);

var:是一个关键字,意思是“我不关心这里的类型是什么。”,系统会自动推断类型runtimeType

但是var定义的变量不能改变类型。

// var关键字,意味着不关心数据类型是什么
    // var定义的数据类型被定义后不能修改
    var a = 'var';
    print(a.runtimeType); //输出:flutter: String
    print(a); // var

    // a = 123;  // 因为a被var定义成String,所以报错
    a = 'deed'; // 正确

Object:是Dart对象的基类,当你定义:Object o=xxx;时这时候系统会认为o是个对象,你可以调用otoString()hashCode()方法。

因为Object提供了这些方法,但是如果你尝试调用o.foo()时,静态类型检查会进行报错。

综上不难看出dynamicObject的最大的区别是在静态类型检查上。

    // Object是Dart对象的基类
    Object o1 = 'deed';
    print(o1.runtimeType); //输出:flutter: String
    print(o1); // deed

4-7 带你揭开Flutter中的面向对象(标准构造方法、初始化列表)

Dart面向对象脑图:
Da
Dart中所有的类都继承自Object

类的构造方法作用:初始化类的对象

类的构造方法1:初始化构造方法

class Person {
  String name;
  int age;

  // Person类初始化方法,标准化构造方法
  Person(this.name, this.age);
  }

多态:通过@override重载父类的方法,如下重载Object类中方法。

  // 重载父类的toString()方法,面向对象多态的体现
  @override
  String toString() {
    return 'name:$name, age:$age';
  }

创建Student类继承Person类:创建子类的构造方法时要初始化父类的构造方法

类的构造方法2:初始化列表,冒号后面的表达式是类的初始化列表,先完成父类的初始化,再完成子类的初始化

class Student extends Person {
// super完成父类的初始化,再完成子类的初始化
 Student(String name, int age) : super(name, age);
 }

类的私有变量通过下划线创建:Dart通过下划线来标识私有变量,类似于private,同理Dart方法也是下划线创建

  String _school; // Dart通过下划线来标识私有变量,类似于private

父类初始化完成后,初始化自有参数:

// 通过this._school初始化自有参数
// name, age交给父类初始化
  Student(this._school, String name, int age) : super(name, age);

构造方法中的可选参数:{}内为可选参数

  // 可选参数
  // city为可选参数
  Student(this._school, name, age, {this.city}) : super(name, age);

构造方法中的默认参数:首先默认参数必须是可选参数,紧接着默认参数赋值

  • _school:私有参数
  • city:可选参数
  • country:默认参数,也是可选参数
  // 默认参数country
  Student(this._school, name, age, {this.city, this.country = 'China'})
      : super(name, age);

类的初始化列表是跟在冒号后面的一串表达式,跟在冒号后面,通过逗号和父类构造方法隔开。

  // 初始化列表表达式
  // 逗号后面是父类构造方法
  Student(this._school, name, age, {this.city, this.country = 'China'})
      : name = '$country.$city',
        super(name, age);

构造方法的方法体可以省略,如下显示构造方法的方法体

  // 构造方法体
  Student(this._school, name, age, {this.city, this.country = 'China'})
      : name = '$country.$city',
        super(name, age) {
    print('构造方法体不是必须的');  // 构造方法的方法提
  }

4-8 带你揭开Flutter中的面向对象(命名构造方法)

命名构造方法:

  • [类名 + . + 方法名],比如Student.cover,其中cover是自定义的方法名
  • 使用命名构造方法为类实现多个构造方法
  • 命名构造方法可以有方法体
  // 命名构造方法: [类名 +1 . + 方法名]
  // 使用命名构造方法为类实现多个构造方法
  // 命名构造方法可以有方法体1
  Student.cover(Student stu) : super(stu.name, stu.age){
    print('命名构造方法');
  }

4-9 带你揭开Flutter中的面向对象(工厂构造方法)

工厂构造方法:返回单例模式,factory关键字
oop_learn.dart

class Logger {
  static Logger _cache; // 静态实例

  // factory关键字,返回唯一的类的实例
  //  工厂构造方法:
  //  不仅仅是构造方法,更是一种模式
  //  有时候为了返回一个之前已经创建的缓存对象,原始的构造方法已经不能满足要求
  //  那么可以使用工厂模式来定义构造方法
  //  对外只暴露了工厂构造方法
  factory Logger() {
    if (_cache == null) {
      _cache = Logger._internal();
    }
    return _cache;
  }

  // 私有的命名构造方法,没有对外暴露
  Logger._internal();

  void log(String msg) {
    print(msg);
  }
}

main.dart:使用工厂构造方法

  void _oopLearn() {
    // 因为Logger类只对外暴露了工厂构造方法Logger() ,所以log1和log2应该相等
    // 即工厂构造方法返回单例
    Logger log1 = Logger();
    Logger log2 = Logger();
    print('----_oopLearn----');
    print(log1 == log2); // 判断log1和log2是否相等 true
  }

输出:可以看到log1和log2实例相等。在这里插入图片描述


4-10 带你揭开Flutter中的面向对象(命名工厂构造方法)

做网络请求的时候,将网络请求的数据转换成模型的时候常用。

命名工厂构造方法:factory [类名 + . + 方法名],形如factory Student.stu(Student stu){}

 // 命名构造方法: [类名 + . + 方法名]
  // 使用命名构造方法为类实现多个构造方法
  // 命名构造方法可以有方法体
  // 因为city是final String,所以必须加入参数
  Student.cover(Student stu, this.city) : super(stu.name, stu.age) {
    print('命名构造方法');
  }

  // 命名工厂构造方法:factory [类名 + . + 方法名]
  // 它可以有返回值,而且不需要将类的final变量作为参数,是提供一种灵活获取类对象的方式
  // 不用加入this.city,相比命名构造方法cover更加灵活
  factory Student.stu(Student stu) {
    return Student(stu._school, stu.name, stu.age);
  }

问题:5种构造方法的实际使用?????

几种构造方法大综合:

 // 标准构造方法
 Student(String name, int age) : super(name, age);

  // 父类初始化完成后,初始化自有参数
 Student(this._school, String name, int age) : super(name, age);

  // 可选参数city
 Student(this._school, name, age, {this.city}) : super(name, age);

  // 默认参数country
  Student(this._school, name, age, {this.city, this.country = 'China'})
       : super(name, age);

  // 初始化列表表达式
  Student(this._school, name, age, {this.city, this.country = 'China'})
      : name = '$country.$city',
         super(name, age);

  // 构造方法体
   Student(this._school, name, age, {this.city, this.country = 'China'})
       : name = '$country.$city',
         super(name, age) {
     print('构造方法体不是必须的');
   }

  // 命名构造方法: [类名 + . + 方法名]
   Student.cover(Student stu, this.city) : super(stu.name, stu.age) {
     print('命名构造方法');
   }

  // 命名工厂构造方法:factory [类名 + . + 方法名]
   factory Student.stu(Student stu) {
     return Student(stu._school, stu.name, stu.age);
   }

感觉初始化列表表达式使用冒号:后面的表达式,也就是用父类Personname值初始化子类Studentname


4-11 带你揭开Flutter中的面向对象(get和set,静态方法)

Flutter面向对象中的方法:
在这里插入图片描述

setget方法类似Java

  // 可以为私有字段设置getter来让外界获取到私有字段
  String get school => _school;

  // 可以为私有字段设置setter来控制外界对私有字段的修改
  set school(String value) {
    _school = value;
  }

静态方法使用:打印时增加字符串doPrint

 // 静态方法
  static doPrint(String str) {
    print('doPrint: $str ');
  }

main.dart中调用:

//  调用工厂构造方法
  void _oopLearn() {
    print('----静态方法调用----');
    Student.doPrint('_oopLearn'); // print('----_oopLearn----');
  }

调用初始化列表表达式:

//  调用工厂构造方法
  void _oopLearn() {
    // 因为Logger类只对外暴露了工厂构造方法Logger() ,所以log1和log2应该相等
    // 即工厂构造方法返回单例
    Logger log1 = Logger();
    Logger log2 = Logger();
    print('----_oopLearn----');
    print(log1 == log2); // 判断log1和log2是否相等 true

    print('----静态方法调用----');
    Student.doPrint('_oopLearn'); // print('----_oopLearn----');

    // 创建Student的对象
    Student stu1 = Student('清华', '成续源', 18);
    stu1.setSchool = '985'; // 调用私有变量的settter方法
    print(stu1.getSchool); // 985
    /// 此处子类Student调用了父类的toString方法,返回的name和age是父类Person的参数
    print(stu1.toString()); // name:China.null, age:12
    /*****
        父类的构造方法初始化了子类
        Student(this._school, String name, int age,
        {this.city, this.country = 'China'})
        : name = '$country.$city',
        age = 12,
        super(name, age);
     **/
  }

子类StudenttoString()方法:

  /// Student子类toString()方法
  @override
  String toString() {
    return '子类toString: \n' +
        'name: $name school: ${this._school} city:$city country:$country \n' +
        '父类toString:\n' +
        '${super.toString()}';
  }

父类PersontoString()方法:

  /// 重载父类的toString()方法,面向对象多态的体现
  @override
  String toString() {
    return 'name:$name, age:$age';
  }

发现的问题?父类的name初始化了子类
在这里插入图片描述

初始化可选参数默认参数

 // flutter: 子类toString:
    // name: 中国.南京 school: 北大 city:南京 country:中国
    // 父类toString:
    // name:中国.南京, age:12
    Student stu2 = Student('北大', '成竹', 19, city: '南京', country: '中国');
    print(stu2.toString());

4-12 带你揭开Flutter中的面向对象(抽象类和方法)

抽象类和抽象方法:比如StatefulWidget就是1个抽象类
在这里插入图片描述
抽象类不能有自己的实例,也就是不能创建自己的对象

抽象类:

  • 使用abstract修饰符定义的类,抽象类不能被实例化
  • 抽象类常用于定义接口
  • 抽象类可以有抽象方法(不包括方法体的方法)
  • 抽象类可以有抽象方法,也可以没有抽象方法
  • 如果1个类有抽象方法,这个类必须被标识成抽象类(abstract修饰)
abstract class Study {
  // 抽象方法(没有方法体的方法)
  void study(); 

  // 正常的方法
  @override
  String toString() {
    return super.toString();
  }
}

继承抽象类:

  • 继承抽象类要实现它的抽象方法,否则也需要将自己定义成抽象类(不实现抽象方法,需要增加abstract修饰符),否则报错
// 没有实现Study中的抽象方法study(),必须用abstract修饰StudyFlutter类,否则报错
abstract class StudyFlutter extends Study {
	
}
  • 实现抽象类中的抽象方法,则不用添加abstract修饰符
class StudyFlutter extends Study {
  // 实现抽象类Study中的抽象方法
  @override
  void study() {
    print('Learning Flutter!');
  }
}

使用抽象类:
main.dart_oopLearn方法

void _oopLearn() {
...

   /// 抽象类用法
    StudyFlutter studyFlutter = StudyFlutter();
    studyFlutter.study(); // Learning Flutter!
}

输出: Learning Flutter!


4-13 带你揭开Flutter中的面向对象(mixins)

mixins:在多个类层次结构中重用代码的1种方式

  • 要使用mixins,需要在with关键字后面跟上1个或多个mixin的名字(用逗号分隔),并且with要用在extends关键字之后
  • 实现mixin,就必须创建1个继承Object类的子类(不能继承其他类),不声明任何构造方法,不调用super
/// 为类添加特征:mixins
/// mixins是在多个类层次结构中重用代码的一种方式
/// 要使用mixins,需要在with关键字后面跟上1个或多个mixin的名字(用逗号分隔),并且with要用在extends关键字之后
/// mixins的特征:实现mixin,就必须创建1个继承Object类的子类(不能继承其他类),不声明任何构造方法,不调用super
/// 如上Study类是mixin
///
/// Test使用了mixins Study
/// 通常在开发中使用mixins复用已经存在的一些类的相关特性
class Test extends Person with Study {
  Test(String name, int age) : super(name, age);

  @override
  void study() {
    // TODO: implement study
  }
}

with Study:即Study类是mixinTest类使用了mixins Study


4-14 带你解锁Flutter中常用的Dart方法类型

Dart中的方法构成和方法类型:
在这里插入图片描述

公有方法

Dart中的方法构成:

  • 返回值 + 方法名 + 参数
  • 其中:返回值类型可缺省,也可为void或具体的类型
  • 方法名:匿名方法不需要方法名
  • 参数:参数类型和参数名,参数类型可缺省(另外,参数又分可选参数和参数默认值,可参考面向对象一节中构造放方法部分)

function_learn.dart:创建sum方法

/// 创建测试类
class TestFunction {
  /// 创建FunctionLearn对象
  FunctionLearn functionLearn = FunctionLearn();

  void start() {
    print(functionLearn.sum(1, 2));  // functionLearn.sum(1, 2)
  }
}

class FunctionLearn {
  /// 方法的构成
  /// 返回值 + 方法名 + 参数
  /// 其中:返回值类型可缺省,也可为void或具体的类型
  /// 方法名:匿名方法不需要方法名
  /// 参数:参数类型和参数名,参数类型可缺省(另外,参数又分可选参数和参数默认值,可参考面向对象一节中构造放方法部分)

  int sum(int val1, int val2) {
    return val1 + val2;
  }
}

私有方法

Dart中的私有方法:方法前加下划线表示私有方法,只能在该类访问

/// 创建测试类
class TestFunction {
  /// 创建FunctionLearn对象
  FunctionLearn functionLearn = FunctionLearn();

 ...

  void privatePrint() {
    functionLearn._learn();
  }
}

class FunctionLearn {

	...

  /// 私有方法
  /// 通过——开头命名的方法
  /// 作用域是当前文件
  _learn() {
    print('私有方法');
  }
}

main.dart中使用公有方法和私有方法:

  void _funtionLearn() {
    TestFunction testFunction = TestFunction();
    testFunction.start();   // 调用公有方法
    testFunction.privatePrint();  // 调用私有方法
  }

匿名方法

class FunctionLearn {
  ///  匿名方法:
  ///  大部分方法都带有名字,例如 main() 或者 print();
  ///  在Dart中你有可以创建没有名字的方法,称之为 匿名方法,有时候也被称为 lambda 或者 closure 闭包;
  ///  你可以把匿名方法赋值给一个变量, 然后你可以使用这个方法,比如添加到集合或者从集合中删除;
  ///  匿名方法和命名方法看起来类似— 在括号之间可以定义一些参数,参数使用逗号 分割,也可以是可选参数;
  ///  后面大括号中的代码为函数体:
  ///  ([[Type] param1[, …]]) {
  ///     codeBlock;
  ///   };
  anonymousFunction() {
    var list = ['私有方法', '匿名方法'];

    /// 下面的代码定义了1个参数为element(该参数没有指定类型)的匿名函数
    /// list中的每个元素都会调用这个函数来打印出来,同时来计算了每个元素在list中的索引位置
    list.forEach((element) {
      print(list.indexOf(element).toString() + ': ' + element); // 打印是第几个元素
    });
  }
}

入口方法

main方法:

void main() {
  runApp(MyApp());
}

4-15 带你了解Dart泛型在Flutter中的应用

在这里插入图片描述

定义泛型类文件genericLearn.dart

import 'package:flutter_dart_learn/opp_learn.dart';

class TestGeneric {
  void start() {
    Cache<String> cache1 = Cache();

    /// 泛型作用:类型检查约束类比:List<String>
    cache1.setItem('cache1', 'cache1');
    String string1 = cache1.getItem('cache1');
    print(string1); // flutter: cache1

    Cache<int> cache2 = Cache();
    cache2.setItem('cache2', 1008);
    print(cache2.getItem('cache2')); // flutter: 2

    Member<Student> member = Member(Student('', '', 16));
    print(member.fixedName()); // flutter: fixed:China.null
  }
}

/// 泛型
/// 通俗理解:泛型主要是解决类、接口、方法的复用性,以及对不特定数据类型的支持
///
/// 泛型类
/// 作用:提高代码的复用度
class Cache<T> {
  static final Map<String, Object> _cached = Map();

  /// 泛型方法
  void setItem(String key, T value) {
    _cached[key] = value;
  }

  T getItem(String key) {
    return _cached[key];
  }
}

/// 有时候你在实现类似通用接口的泛型中,期望的类型是某些特定类型时,这时可以使用类型约束
class Member<T extends Person> {
  T _person;

  /// 泛型作用:约束参数类型
  Member(this._person);

  String fixedName() {
    return 'fixed:${_person.name}';
  }
}

main.dart中使用泛型方法:

  /// 泛型
  void _genericLearn() {
    TestGeneric testGeneric = TestGeneric();
    testGeneric.start();
  }

4-16 有哪些可以在Flutter上的编程技巧

编程技巧:skills_learn.dart
在这里插入图片描述

安全的调用

对于不确定是否为空的对象通过?.的来访问它的属性或方法以防止空异常,如:a?.foo()

  List list;

  /// Dart编程小技巧1:安全的调用
  /// 对于不确定是否为空的对象可以通过?.的方式来访问它的属性或方法以防止空异常,如:a?.foo()
  print(list?.length); // null

使用??设置默认值

list.length为空的时候,默认值为-1

  print(list?.length ?? -1); // -1

类似ES6中的简化判断

使用contains方法:

  list = [];
  list.add(0);
  list.add('');
  list.add(null);
  
 if (list[0] == null || list[0] == '' || list[0] == 0) {
    print('list[0] is empty!'); // list[0] is empty!
  }

等价于

 /// 简化代码判断,类似ES6方法
  if ([null, '', 0].contains(list[0])) {
    print('list[0] is empty!'); // list[0] is empty!
  }

4-17 小结

学习资料:

Dart中文网
Dart官网


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值