• Flutter(学前必看)基础


    所有Widget汇总

    Flutter组件的分类
    1、基础组件
    文本,Text
    按钮,TextButton等
    图片图标,Image、Icon
    输入框 和 表单,TextField、Form
    进度指示器,LinearProgressIndicator、CircularProgressIndicator
    单选框和复选框,Switch、Checkbox
    
    2、布局之容器组件
    装饰,DecoratedBox、BoxDecoration等,如颜色、背景、边框、渐变、阴影等
    复合容器,Container,它是结合align、padding、margin、box、变换等多种功能。
    尺寸,主要是设置页面的宽高大小 或 宽高比例。
    宽高SizedBox、AspectRatio、LimitedBox、FractionallySizedBox等;
    限制类ConstrainedBox、BoxConstraints、UnconstrainedBox等
    对齐,Align
    居中,Center
    填充,Padding
    剪裁,ClipOval、ClipPath、ClipRect、ClipRRect等
    变换(如旋转等),Transform
    适配(如换行,即超出父组件边界约束),FittedBox
    
    3、布局组件
    线性布局,Row、Column
    弹性布局,Flex、Expanded
    流式布局(子元素自动换行),Wrap、Flow
    层叠布局,Stack、Positioned
    
    4、复合组件(滚动、列表等)
    简单滚动列表(类似iOS的ScrollView),SingleChildScrollView
    列表,ListView、AnimatedList
    二维列表(类似iOS的CollectionView),GridView
    自定义滚动列表,CustomScrollView、NestedScrollView
    TabBar,TabBarView
    
    5、交互组件
    手势,GestureDetector、GestureRecognizer等相关类
    动画,Animation、Curve、AnimationController、Tween、Ticker等相关类
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    组件类以及继承关系
    一、组件基类
    abstract class DiagnosticableTree with Diagnosticable
    abstract class Widget extends DiagnosticableTree
    
    二、普通组件
    abstract class StatelessWidget extends Widget
    abstract class StatefulWidget extends Widget
    
    // 状态
    abstract class State<T extends StatefulWidget> with Diagnosticable
    
    
    三、布局组件
    // 布局类基类
    abstract class RenderObjectWidget extends Widget 
    
    // 包含一个子Widget,如:ConstrainedBox、DecoratedBox等
    abstract class SingleChildRenderObjectWidget extends RenderObjectWidget 
      通过属性child关联单个widget
    
    // 包含多个子Widget,一般都有一个children参数,接受一个Widget数组。如Row、Column、Stack等
    abstract class MultiChildRenderObjectWidget extends RenderObjectWidget 
      通过属性children关联多个widget。
    
    // Widget树的叶子节点,用于没有子节点的widget,通常基础组件都属于这一类,如Image。
    abstract class LeafRenderObjectWidget extends RenderObjectWidget 
    
    // Widget代理
    abstract class ProxyWidget extends Widget
    abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget
    
    // 弹性布局,flex
    class Flex extends MultiChildRenderObjectWidget
    
    class Flexible extends ParentDataWidget<FlexParentData>
    class Expanded extends Flexible
    
    // 线性布局
    class Column extends Flex
    class Row extends Flex
    
    // 设置padding
    class Padding extends SingleChildRenderObjectWidget
    // SizedBox 设置宽高
    class SizedBox extends SingleChildRenderObjectWidget
    // Spacer 基于flex的空白,内部基于Expanded实现的,它只是Expanded的一个包装类
    class Spacer extends StatelessWidget
    
    // 流式布局
    class Wrap extends MultiChildRenderObjectWidget
    class Flow extends MultiChildRenderObjectWidget
    
    // 层叠布局
    class Stack extends MultiChildRenderObjectWidget
    class Positioned extends ParentDataWidget<StackParentData>
    
    // 对齐与相对定位
    class Align extends SingleChildRenderObjectWidget
    class Center extends Align
    
    /* 容器类组件*/
    // 填充
    class Padding extends SingleChildRenderObjectWidget
    
    // 尺寸大小限制
    class ConstrainedBox extends SingleChildRenderObjectWidget
    class SizedBox extends SingleChildRenderObjectWidget
    class AspectRatio extends SingleChildRenderObjectWidget
    class FractionallySizedBox extends SingleChildRenderObjectWidget
    class LimitedBox extends SingleChildRenderObjectWidget
    
    class UnconstrainedBox extends StatelessWidget
    
    // 装饰类组件
    class DecoratedBox extends SingleChildRenderObjectWidget
    class BoxDecoration extends Decoration
    
    // 组合类容器
    class Container extends StatelessWidget
    
    
    /* Material常用组件类 */
    class Scaffold extends StatefulWidget
    
    abstract class PreferredSizeWidget implements Widget
    class AppBar extends StatefulWidget implements PreferredSizeWidget
    
    class Drawer extends StatelessWidget
    class FloatingActionButton extends StatelessWidget
    
    class BottomNavigationBar extends StatefulWidget 
    class BottomNavigationBarItem
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    Dart语法

    一、Hello Dart

    1.入口

    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • void代表没有返回值
    • 定义字符串的时候,可以使用单引号或双引号
    • 每行语句必须使用分号结尾

    2.打印

    //使用字符串插值($或者${name}) 来打印包含变量的字符串
    void main() {
      String name = "Alice";
      int age = 25;
      print("My name is $name and I am $age years old.");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    二、定义变量

    var/dynamic/const/final

    var

    Dart 中 var 变量一旦赋值,类型便会确定,则不能再改变其类型

    var t = "hi world";
    // 下面代码在dart中会报错,因为变量t的类型已经确定为String,
    // 类型一旦确定后则不能再更改其类型。
    t = 1000;
    
    • 1
    • 2
    • 3
    • 4
    dynamic与Object

    dynamic与Object声明的变量都可以赋值任意对象,且后期可以改变赋值的类型,不同的是dynamic声明的对象编译器会提供所有可能的组合,而Object声明的对象只能使用 Object 的属性与方法, 否则编译器会报错

    dynamic a;
     Object b = "";
     main() {
       a = "";
       printLengths();
     }   
    
     printLengths() {
       // 正常
    print(a.length);
       // 报错 The getter 'length' is not defined for the class 'Object'
       print(b.length);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    final 或 const

    不可更改变量,使用 final 或 const,两者区别在于:const 变量是一个编译时常量(编译时直接替换为常量值),final变量在第一次使用时被初始化。被final或者const修饰的变量,变量类型可以省略

    //可以省略String这个类型声明
    final str = "hi world";
    //final String str = "hi world"; 
    const str1 = "hi world";
    //const String str1 = "hi world";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    空安全(null-safety)
    int i = 8; //默认为不可空,必须在定义时初始化。
    int? j; // 定义为可空类型,对于可空变量,我们在使用前必须判空。
    
    // 如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,
    // 表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错
    late int k;
    k=9;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、数据类型

    基本类型

    int age = 12;
    double price = 10.0;
    String name = "张飞";
    String name2 = '张飞';//单双引号没区别
    //多行字符串
    String name3 = '''
    张飞
    诸葛亮
    廉颇
    ''';
    bool sex = false;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    集合

    list/set/map
    var nameList = ["张飞","关羽","刘备"];
    List<String> nameList2 =["张飞","关羽","刘备"];
    List<String> nameList3 = [];
    
    var nameSet = {"张飞","关羽","刘备"};
    Set<String> nameSet2 = {"张飞","关羽","刘备"};
    Set<String> nameSet3 = {};
    
    var map = {"name": "张飞", "height": 1.88};
    Map<String, Object> map2 = {"name": "张飞", "height": 1.88};
    Map<String, Object> map3 = {};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    四、函数

    函数返回值

    //无返回值
    void fun1(){
      
    }
    //有返回值
    int fun2(){
      return 1;
    }
    //单行简写
    int fun3()=>1;
    
    //返回类型 void  和 int 也可以省略
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    可选参数

    注意, 只有可选参数才可以有默认值, 必须参数不能有默认值

    //命名可选参数: {param1, param2, ...}
    //位置可选参数: [param1, param2, ...]
      
    //命名可选参数
    optionParamsFun1(String name, {int age = 10, double height = 1.8}) {
        print('$name,$age,$height');
    }
    //required 标识为必选参数
    optionParamsFun2(String name, {int age = 10,required double height}{
      print('$name,$age,$height');
    
    }
    //调用
    optionParamsFun1('yh');
    optionParamsFun1('yh',age: 20);
    optionParamsFun1('yh',age: 20,height: 1.88);
    // yh,10,1.8
    // yh,20,1.8
    // yh,20,1.88
    
    //位置可选参数
    optionParamsFun1(String name, [int age = 10, double height = 1.8]) {
        print('$name,$age,$height');
    }
    optionParamsFun1('yh');
    optionParamsFun1('yh', 20);
    optionParamsFun1('yh', 20, 1.88);
    // yh,10,1.8
    // yh,20,1.8
    // yh,20,1.88
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    函数作为参数、返回值

    //调用
    test(){
      getFunc();
      test2(foo("张飞"));
    }
    
    //1.定义一个函数
    foo(String name) {
      print(name);
    }
    //2.将函数作为另一个函数的返回值
    getFunc() {
      return foo;
    }
    //3.将函数作为另一个函数的参数
    test2(Function func) {
      func("func");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    匿名函数

    void main3() {
      var numbers = [1, 2, 3, 4, 5];
      
      //遍历
      numbers.forEach((element) {
        print(element);
      });
    
      // 使用匿名函数对列表中的每个元素进行平方
      var squaredNumbers = numbers.map((number) => number * number);
    
      print(squaredNumbers.toList()); // 输出: [1, 4, 9, 16, 25]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    五、运算符

    除法、整除、取余

      var num = 7;
      print(num / 3);//除 2.3333
      print(num ~/ 3);//整除 2
      print(num % 3);//取余 1
    
    • 1
    • 2
    • 3
    • 4

    ??= 和 ?? 和 。。和?:

    test1(){
    //当变量不为null时使用变量,
      var name = 'lucy';
      name ??= 'sala';
      print(name);//lucy
    //当变量为null时,后面的值将被赋值给变量
      var name2 = null;
      name2 ??= 'Toms';
      print(name2);//Toms
    
    //如果a>10,b就等于a,否则b = 11
     int a = 5;
     int b = a>10?a:11;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    //当变量不为null时使用变量,
      var name = 'lucy';
      print(name ?? 'sala');//lucy
    //当变量为null时使用后面的值
      var name2 = null;
      print(name2 ?? 'Toms');//Toms
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    类型判定运算符

    as 将对象强制转换为特定类型。
    is 和 is! 判断变量是不是某种类型。

    级联操作符(。。)
    class Person {
      String name = 'Tom';
      void eat() {
      }
      void drink() {
      }
      void sleep() {
      }
    }
    //..可以连续访问方法和属性(类似返回值为Person)
    void test2(){
      Person()..name..eat()..drink()..sleep();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    list、set、map的for循环

    void test2(){
      List<String> names = ['Alice', 'Bob', 'Charlie'];
      //普通遍历
      for (int i = 0; i < names.length; i++) {
        print(names[i]);
      }
      //forEach 遍历
      names.forEach((name) {
        print(name);
      });
      //遍历的同时转换为大写
      List<String> upperCaseNames = names.map((name) => name.toUpperCase()).toList();
      print(upperCaseNames);
      //in 遍历
      for (String name in names) {
        print(name);
      }
    
    
    
      Set<String> mySet = {'A', 'B', 'C'};
      for (var item in mySet) {
        print(item);
      }
    
      mySet.forEach((item) {
        print(item);
      });
    
      //转为list然后遍历
      List<String> myList = mySet.toList();
      for (var item in myList) {
        print(item);
      }
    
    
    
      Map<String, dynamic> myMap = {'key1': 'value1', 'key2': 'value2'};
      //遍历键值对
      for (var entry in myMap.entries) {
        print('${entry.key}: ${entry.value}');
      }
      //遍历键值对
      myMap.forEach((key, value) => print('$key: $value'));
    
      //遍历键
      myMap.keys.forEach((key) => print(key));
    
      //遍历值
      myMap.values.forEach((value) => print(value));
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    while 和 do-while

    while :先检查条件,再执行

    int i = 0;
    while (i < 5) {
      print(i);
      i++;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    do-while :先执行,再检查

    int i = 0;
    do {
      print(i);
      i++;
    } while (i < 5);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    break和continue

    for循环中,我们可以使用"break"关键字来提前结束循环

    for (int i = 0; i < 10; i++) {
      if (i == 5) {
        break;
      }
      print(i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用"continue"时,会跳过当前迭代的剩余代码,直接进入下一次迭代

    for (int i = 0; i < 10; i++) {
      if (i % 2 != 0) {
        continue;
      }
      print(i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    六、类

    void main(List<String> args) {
    //实例化
      var p1 = Person();
      p1.eat();
    }
    
    class Person {
      String name = 'Tom';
    
      void eat() {
        String name = 'lucy';
        print(name);//lucy
        print(this.name);//Tom
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    构造方法

    Dart为类提供了默认的构造函数,当有了自己的构造函数,默认的构造方法将会失效,

    在Flutter中,构造方法有几种方式:默认、命名、工厂、常量

    默认构造方法:这是最常见的构造方法,它没有任何参数。例如:
    复制代码

    class MyClass {
      MyClass() {
        // 构造方法的逻辑
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    命名构造方法:使用命名构造方法可以为类提供多个不同的构造方法,每个构造方法可以有不同的参数。例如:

    class MyClass {
      MyClass() {
        // 默认构造方法
      }
      
      MyClass.namedConstructor() {
        // 命名构造方法
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在使用命名构造方法时,可以通过指定构造方法的名字来调用它。

    带参数的构造方法

    class MyClass {
      int value;
      
      MyClass(int value) {
        this.value = value;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    工厂构造方法:可以返回一个已经存在的实例,或者返回一个子类的实例。例如:

    class MyClass {
      factory MyClass() {
        return _singleton;
      }
      
      MyClass._internal();
      
      static final MyClass _singleton = MyClass._internal();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这个例子中,工厂构造方法返回一个单例实例。

    常量构造方法,成员变量必须是final修饰,使用const关键字实例化

    class Person {
      final String name;
      final int age;
    
      const Person(this.name,this.age);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    枚举

    void main(List<String> args) {
      print(Colors.red);
      //枚举属性 index索引,从0开始;values包含所有枚举值的list
      print(Colors.red.index);
      print(Colors.values);
    }
    
    enum Colors {
      red,
      green,
      blue
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    单例模式

    //写法一
    class Singleton {
      const Singleton._internal();
      factory Singleton() => const Singleton._internal();
    }
    Singleton single = Singleton();
    
    //写法二
    class Singleton {
      Singleton._privateInstance();
      static final Singleton instance = Singleton._privateInstance();
      factory Singleton(){
        return instance;
      }
    }
    //使用
    Singleton single = Singleton();
    
    //写法三
    class Singleton {
      Singleton._internal();
      static final Singleton _instance = Singleton._internal();
      static Singleton getInstance() {
        return _instance;
      }
    }
    //使用
    var instance = Singleton.getInstance();
    
    //写法四
    class Singleton {
    	// 私有化构造方法
    	Singleton._privateConstructor();
    	static final Singleton _instance = Singleton._privateConstructor();
    	//同下 : static Singleton get instance => _instance;
    	static Singleton get instance { return _instance;}
    }
    //使用
    var instance = Singleton.instance;
    
    //写法五
    class Singleton {
    	Singleton._privateConstructor();
    	static final Singleton instance = Singleton._privateConstructor();
    }
    //使用
    void mian(){
    	var instance = Singleton.instance;
        var instance2 = Singleton.instance;
        print(instance == instance2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    setter和getter

    class Person {
      var name;
    
      set setName(String nameStr){
        name = nameStr;
      }
    
      String get getName{
        print('getName');
        return name;
      }
    }
    
      Person p = Person();
      p.name = '123';
      print(p.getName);//getName  123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    继承 extends

    class Person {
      var name;
    
      Person(this.name);
    
      set setName(String nameStr){
        name = nameStr;
      }
    
      String get getName{
        print('getName');
        return name;
      }
    
      eat() {
      }
    
      run(){
        print('person run');
      }
    }
    
    class Student extends Person {
      int age;
      Student.withAge(String name, this.age): super(name);
    
      @override
      run() {
        // TODO: implement run
        super.run();
        print('student run');
      }
    }
    
    test(){
      Student s =  Student.withAge('Tom', 18);
      s.name = '123';
      print(s.getName);//getName  123
      s.run();
      //person run
    // student run
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    抽象类 abstract

    abstract class Animal {
      eat();
      run(){
      }
    }
    
    class Dog extends Animal {
    
      @override
      eat() {
        // TODO: implement eat
      }
    
    }
    
    class SmallDog extends Dog {
      @override
      run() {
        // TODO: implement run
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    隐式接口 implements

    Dart中的接口比较特殊, 没有一个专门的关键字来声明接口.
    默认情况下,定义的每个类都相当于默认也声明了一个接口,可以由其他的类来实现(因为Dart不支持多继承)

     class Eat {
      eat() {
      }
    }
    abstract class Run {
      run() {
    
      }
    }
    
    class Animal implements Eat,Run {
    
      @override
      run() {
        // TODO: implement run
      }
    
      @override
      eat() {
        // TODO: implement eat
        throw UnimplementedError();
      }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Mixin混入 mixin with

    除了通过class定义类,也可以通过mixin定义一个类。
    通过mixin定义的类用于被其他类混入使用,通过with关键字来进行混入。

    mixin Eat {
      eat();
    }
    mixin Run {
      run(){
      }
    }
    
    class Animal with Eat,Run {
    
      @override
      eat() {
        // TODO: implement eat
      }
      // @override
      // run() {
      //   // TODO: implement run
      // }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    七、泛型

    //泛型写法 
      // List
      //_InternalLinkedHashMap
      var list = ['a','b','c',123];
      var dic = {'key1':'value1', 'key2':123};
      //限制类型
      var list2 = <String>['a','b','c'];
      var dic2 = <String, String>{'key1':'value1', 'key2':'value2'};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Object类型 和 T泛型

    //object
    class Person {
      Object name;
      Object age;
      Person(this.name, this.age);
    }
    
      Person p = Person('yh',18);
      print(p.name.runtimeType);
      print(p.age.runtimeType);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    //T
    class Person<T extends num> {
      T age;
      T height;
      Person(this.age, this.height);
    
      double sum(){
        double s = (this.age as int) * (this.height as double);
        return s;
      }
    }
    
      Person p = Person(10,1.88);
      print(p.age.runtimeType);// int
      print(p.sum());// 18.799999999999997
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    空安全 “?”和“!”

    //age可以为null
    int? age = null;
      age = 10;
      //!表示age必然不为null
      double height = age! * 10.0;
      print(height);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    八、库

    库的导入

    常见的库URI有三种不同的形式

    来自dart标准版,比如dart:io、dart:html、dart:math、dart:core(但是这个可以省略)

    //dart:前缀表示Dart的标准库,如dart:io、dart:html、dart:math
    import 'dart:io';
    
    • 1
    • 2

    使用相对路径导入的库,通常指自己项目中定义的其他dart文件

    //当然,你也可以用相对路径或绝对路径的dart文件来引用
    import 'lib/student/student.dart';
    
    • 1
    • 2

    Pub包管理工具管理的一些库,包括自己的配置以及一些第三方的库,通常使用前缀package

    //Pub包管理系统中有很多功能强大、实用的库,可以使用前缀 package:
    import 'package:flutter/material.dart';
    
    • 1
    • 2

    库文件中内容的显示和隐藏:
    如果希望只导入库中某些内容,或者刻意隐藏库里面某些内容,可以使用show和hide关键字

    //show关键字:可以显示某个成员(屏蔽其他)
    //hide关键字:可以隐藏某个成员(显示其他)
    import 'lib/student/student.dart' show Student, Person;
    import 'lib/student/student.dart' hide Person;
    
    • 1
    • 2
    • 3
    • 4

    当各个库有命名冲突的时候,可以使用as关键字来使用命名空间

    //库中内容和当前文件中的名字冲突
    import 'lib/student/student.dart' as Stu;
    Stu.Student s = new Stu.Student();
    
    • 1
    • 2
    • 3

    库的定义

    library关键字
    通常在定义库时,我们可以使用library关键字给库起一个名字。

    但目前我发现,库的名字并不影响导入,因为import语句用的是字符串URI

    library math;
    
    • 1

    part关键字
    在之前我们使用student.dart作为演练的时候,只是将该文件作为一个库。

    在开发中,如果一个库文件太大,将所有内容保存到一个文件夹是不太合理的,我们有可能希望将这个库进行拆分,这个时候就可以使用part关键字了

    不过官方已经不建议使用这种方式了:
    mathUtils.dart文件

    part of "utils.dart";
    
    int sum(int num1, int num2) {
      return num1 + num2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    dateUtils.dart文件

    part of "utils.dart";
    
    String dateFormat(DateTime date) {
      return "2020-12-12";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    utils.dart文件

    part "mathUtils.dart";
    part "dateUtils.dart";
    
    • 1
    • 2

    test_libary.dart文件

    import "lib/utils.dart";
    
    main(List<String> args) {
      print(sum(10, 20));
      print(dateFormat(DateTime.now()));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    export关键字
    官方不推荐使用part关键字,那如果库非常大,如何进行管理呢?

    将每一个dart文件作为库文件,使用export关键字在某个库文件中单独导入
    mathUtils.dart文件

    int sum(int num1, int num2) {
      return num1 + num2;
    }
    
    • 1
    • 2
    • 3

    dateUtils.dart文件

    String dateFormat(DateTime date) {
      return "2020-12-12";
    }
    
    • 1
    • 2
    • 3

    utils.dart文件

    library utils;
    
    export "mathUtils.dart";
    export "dateUtils.dart";
    
    • 1
    • 2
    • 3
    • 4

    test_libary.dart文件

    import "lib/utils.dart";
    
    main(List<String> args) {
      print(sum(10, 20));
      print(dateFormat(DateTime.now()));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    也可以通过Pub管理自己的库。

    九、多线程

    异步

    1、使用async/await语法:使用async关键字定义一个异步函数,并在需要进行异步操作的地方使用await关键字来等待异步操作的结果。例如:

    Future<int> fetchData() async {
      await Future.delayed(Duration(seconds: 1));
      return 42;
    }
    
    void main() async {
      print("Start");
      int result = await fetchData();
      print("Result: $result");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、使用Future对象:可以使用Future对象来表示一个异步操作,并使用then方法来处理异步操作的结果。例如:

    Future<int> fetchData() {
      return Future.delayed(Duration(seconds: 1), () => 42);
    }
    
    void main() {
      print("Start");
      fetchData().then((result) {
        print("Result: $result");
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    whenComplete:Future 完成(无论是成功还是失败)后调用该回调函数

    Future<int> fetchSomeData() async {
      // 模拟异步操作
      await Future.delayed(Duration(seconds: 2));
      
      // 返回一个成功的结果
      return 42;
    }
    
    void main() {
      fetchSomeData()
        .then((value) {
          print('成功获取到数据:$value');
        })
        .catchError((error) {
          print('获取数据时发生错误:$error');
        })
        .whenComplete(() {
          print('无论成功或失败,都会执行这个回调函数');
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    fetchSomeData 函数模拟了一个异步操作,它会在2秒后返回一个成功的结果。在 main 函数中,我们使用 .then 方法注册了一个成功时的回调函数,并使用 .catchError 方法注册了一个失败时的回调函数。最后,我们使用 .whenComplete 方法注册了一个无论成功或失败都会执行的回调函数。

    3.使用Stream对象:Stream是一种用于处理异步数据流的对象,可以通过添加监听器来处理异步操作的结果。例如:

    Stream<int> fetchData() {
      return Stream.periodic(Duration(seconds: 1), (count) => count).take(3);
    }
    
    void main() {
      print("Start");
      fetchData().listen((result) {
        print("Result: $result");
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    以上是Flutter中几种常见的实现异步操作的方式

    flutter Stream 和Future的区别?

    在Flutter中,Stream和Future是用于处理异步操作的两种不同的机制。

    Future是一种表示异步操作结果的对象。它通常用于表示一次性的操作,例如从网络获取数据或执行耗时任务。当一个Future对象被创建时,它立即开始执行,并且可以通过await关键字来等待其结果。Future只能返回一个结果,并且一旦结果可用,它将不会再次改变。您可以通过使用.then()方法或async/await语法来处理Future的结果。

    Stream是一种表示一系列异步操作结果的对象。它通常用于表示实时或连续的数据流,例如从数据库查询结果或用户输入事件。当一个Stream对象被创建时,它并不会立即开始执行,而是每当有新的数据可用时,会通过事件的形式传递给监听器。您可以使用StreamSubscription来监听Stream的事件,并对每个事件做出相应的处理。

    因此,Future适用于一次性的异步操作,而Stream适用于连续的异步数据流。在使用时,您可以根据具体需求来选择使用Future还是Stream。

    计算密集型任务

    Flutter中的compute函数是一个用于在Isolate中执行计算密集型任务的函数。Isolate是Dart中的一个概念,它类似于线程,但是具有独立的内存空间,可以并行执行任务。

    使用compute函数,可以将计算密集型的任务从主线程中分离出来,以避免阻塞UI线程,从而提高应用的性能和响应能力。

    下面是compute函数的基本用法示例:

    import 'dart:async';
    import 'package:flutter/foundation.dart';
    
    Future<int> calculate(int n) async {
      // 在这里执行计算密集型任务
      int result = 0;
      for (int i = 1; i <= n; i++) {
        result += i;
      }
      return result;
    }
    
    void main() async {
      // 使用compute函数在Isolate中执行计算任务
      int result = await compute(calculate, 1000000);
      print(result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在上面的示例中,calculate函数是一个计算密集型的任务,它将对1到给定参数n之间的所有数字求和。main函数使用compute函数调用calculate函数,并传递一个参数1000000。compute函数会将calculate函数发送到一个新的Isolate中执行,并返回计算结果。

    十、Widget

    1. flutter StatefulWidget和StatelessWidget的区别?

    StatefulWidget和StatelessWidget是Flutter中用于构建用户界面的两种基本组件类型。

    StatefulWidget是有状态的组件,它依赖于一个状态对象(State)来管理和维护数据。当这个状态对象发生变化时,StatefulWidget会触发重新构建,从而更新界面。StatefulWidget适用于需要根据数据动态更新界面的场景,比如表单输入、计数器等。

    StatelessWidget是无状态的组件,它不依赖于任何状态对象,一旦创建就不会再改变。StatelessWidget适用于静态内容的展示,比如文本、图像等。

    选择使用StatefulWidget还是StatelessWidget取决于你的界面是否需要动态更新
    如果界面的展示内容不随任何状态信息的变化而变化,可以选择使用StatelessWidget;
    如果界面的展示内容需要根据数据动态更新,可以选择使用StatefulWidget。

    2. flutter StatefulWidget和StatelessWidget的应用场景?

    在实际使用中,应根据具体情况来选择适合的组件类型。如果界面只有一些静态内容,没有交互和状态变化,可以使用StatelessWidget;如果界面需要有交互和状态变化,可以使用StatefulWidget。

    需要注意的是,过度使用StatefulWidget可能会影响应用的渲染性能。因为StatefulWidget的更新会触发整个界面的重新构建,包括所有子组件的销毁和重建。所以在选择组件类型时,需要综合考虑界面的动态性和性能需求。

    总结来说,
    StatefulWidget适用于需要根据数据动态更新界面的场景,
    而StatelessWidget适用于静态内容的展示。
    正确选择组件类型可以提高应用的性能和开发效率。

    基础组件

    Text(文本)相关
    Text(
      'Hello, world!',
      style: TextStyle(
        fontSize: 20,
        color: Colors.blue,
      ),
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //RichText是用来展示富文本的组件,它支持多种样式的文本混合在一起展示
    RichText(
      text: TextSpan(
        text: 'Hello',
        style: TextStyle(color: Colors.black),
        children: <TextSpan>[
          TextSpan(
            text: 'world',
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          TextSpan(
            text: '!',
            style: TextStyle(color: Colors.red),
          ),
        ],
      ),
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    //允许用户选择和复制文本内容
    SelectableText(
      'Hello, World!',
      style: TextStyle(fontSize: 20),
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    TextField(输入)相关
    TextField(
      decoration: InputDecoration(
        labelText: '请输入文本',
      ),
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    //与TextField类似,但提供了更多的验证和表单功能。
    Form(
      child: TextFormField(
        decoration: InputDecoration(
          labelText: '请输入文本',
        ),
        validator: (value) {
          if (value.isEmpty) {
            return '请输入文本';
          }
          return null;
        },
      ),
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    //一个iOS风格的文本输入框控件
    CupertinoTextField(
      placeholder: '请输入文本',
    )
    
    • 1
    • 2
    • 3
    • 4
    //SearchDelegate是Flutter中的一个抽象类,可以用来实现搜索功能。
    //要使用SearchDelegate,需要先创建一个继承自SearchDelegate的子类,并实现一些必要的方法。
    class CustomSearchDelegate extends SearchDelegate {
      @override
      List<Widget> buildActions(BuildContext context) {
        return [
          IconButton(
            icon: Icon(Icons.clear),
            onPressed: () {
              query = '';
            },
          ),
        ];
      }
    
      @override
      Widget buildLeading(BuildContext context) {
        return IconButton(
          icon: Icon(Icons.arrow_back),
          onPressed: () {
            close(context, null);
          },
        );
      }
    
      @override
      Widget buildResults(BuildContext context) {
        // 在这里处理搜索结果的展示
        return Container();
      }
    
      @override
      Widget buildSuggestions(BuildContext context) {
        // 在这里处理搜索建议的展示
        return Container();
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在buildActions方法中,我们可以添加一些操作按钮,比如清除搜索内容的按钮。buildLeading方法用于创建返回按钮。buildResults方法中可以展示搜索结果,buildSuggestions方法中可以展示搜索建议。

    Button(按钮)相关
    TextButton(
      onPressed: () => print('TextButton pressed'),
      child: Text('Btn'),
    ),
    ElevatedButton(
      onPressed: () => print('ElevatedButton pressed'),
      child: Text('Btn'),
    ),
    OutlinedButton(
      onPressed: () => print('OutlinedButton pressed'),
      child: Text('Btn'),
    ),
    IconButton(
      onPressed: () => print('IconButton pressed'),
      icon: Icon(Icons.add),
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    flutter TextButton、ElevatedButton 和 OutlinedButton 和 IconButton的区别?

    TextButton、ElevatedButton、OutlinedButton和IconButton是Flutter中的不同类型的按钮控件,它们在外观和功能上有一些区别。

    TextButton(文本按钮):TextButton是一个扁平化的按钮,没有背景颜色,默认透明。点击时会出现墨水飞溅效果。TextButton通常用于需要较为简洁和清晰的界面设计。

    ElevatedButton(凸起按钮):ElevatedButton是一个凸起的按钮,带有一个默认的背景颜色。点击时会有一个升起的动画效果。ElevatedButton通常用于需要突出显示的操作,比如提交表单或重要的用户交互。

    OutlinedButton(轮廓按钮):OutlinedButton是一个带有边框的按钮,没有背景颜色,默认透明。点击时会出现墨水飞溅效果。OutlinedButton通常用于需要较为轻量级的操作,比如取消或返回。

    IconButton(图标按钮):IconButton是一个只包含图标的按钮,没有文字内容。IconButton通常用于需要仅使用图标表示操作的场景。

    更多:

    Dart 方方面面▩Dart-可迭代集合
    Flutter:组件Widget
    Flutter 布局详解十篇
    dart 和 FlutterFlutter:第三方常用库整理

    推荐:Flutter学习笔记(汇总)

  • 相关阅读:
    神经网络准确率计算公式,提高神经网络精确率
    阿里P8架构师进阶心得:分布式数据库架构MyCat学习笔记送给你
    ThinkingPython | 关于Programing 和 Debugging的认识
    算法通关村第十六关:白银挑战-滑动窗口经典问题
    Jmeter(四) - 从入门到精通 - 创建网络测试计划(详解教程)
    传音控股Android一面凉经(2024)
    Spring Boot通过企业邮箱发邮件被Gmail退回的问题解决方法
    20221125使用PR2023自动识别obs-studio录屏生成的MKV视频的字幕
    k8s--基础--16--Service--理论
    安卓开发Android studio学习笔记14:用户注册登录(案例演示)
  • 原文地址:https://blog.csdn.net/zx_android/article/details/134039956