• Flutter学习笔记


    此篇文章用来记录学习Flutter 和 Dart 相关知识


    零.Dart基本数据类型

    Dart 是一种静态类型的编程语言,它提供了一系列基本数据类型,用于存储和操作不同种类的数据。以下是 Dart 中的一些基本数据类型以及它们的详细介绍:

    1. 整数类型(Integer):

    Dart 提供了两种整数类型:int 和 num。
    int 表示整数,可以存储正数、负数和零。
    num 是 int 和 double 的超类型,可以用来表示整数和浮点数。

    int age = 30;
    num temperature = 98.6;
    
    • 1
    • 2

    2. 浮点数类型(Double):

    Dart 中的浮点数类型为 double,用于表示带有小数点的数值。

    double pi = 3.14159;
    
    • 1

    3.字符串类型(String):

    字符串类型用于表示文本数据。
    字符串可以由单引号或双引号包围。

    String greeting = 'Hello, Dart!';
    
    • 1

    4.布尔类型(Boolean):

    布尔类型只有两个值:true 和 false,用于表示逻辑真值和假值。

    bool isDartFun = true;
    
    • 1

    5.列表类型(List):

    列表是有序的数据集合,可以包含不同类型的元素。
    列表使用方括号 [] 定义,并可以通过索引访问元素。

    List<int> numbers = [1, 2, 3, 4, 5];
    
    • 1

    6.映射类型(Map):

    映射是一组键值对的集合,其中每个键都与一个值相关联。
    映射使用大括号 {} 定义。

    Map<String, int> grades = {'Alice': 90, 'Bob': 85, 'Carol': 92};
    
    • 1

    7.符号类型(Symbol):
    符号类型用于表示运行时的标识符或运算符。
    符号使用 # 符号前缀定义。

    Symbol mySymbol = #myIdentifier;
    
    • 1

    8.空类型(Null):

    Dart 有一个特殊的数据类型 Null,表示一个空值或缺失值。
    在非空安全(null-safe)的 Dart 中,所有的变量默认都不可以为 null,需要使用 ? 明确标记为可为 null。

    String? nullableString = null; // 可为 null 的字符串
    
    • 1

    9.动态类型(Dynamic):

    dynamic 是 Dart 中的一个特殊类型,可以存储任意类型的数据。
    使用 dynamic 声明的变量可以在运行时改变其类型。

    dynamic dynamicVariable = 42;
    dynamicVariable = 'Hello';
    
    
    • 1
    • 2
    • 3

    这些是 Dart 中的一些基本数据类型。Dart 还支持更多高级数据类型,例如函数、类、枚举等,以便更灵活地处理各种数据和逻辑。此外,Dart 2.12 引入了非空安全(null safety)功能。
    注意
    Dart 中没有专门的字节数据类型,而是使用 int 来表示字节值,因为 Dart 的整数类型 int 可以存储 8 位的无符号整数,正好对应一个字节。如果你需要表示多个字节的数据,可以使用列表 (List) 或字节数组 (Uint8List,通常需要导入 dart:typed_data 库)。

    一.Dart 一些语法

    const:关键字,用于声明一个编译时常量

    变量声明
    const int x = 5;
    
    构造函数: 用于声明一个可以在编译时确定值的常量构造函数。
    class MyClass {
      final int value;
      const MyClass(this.value);
    }
    
    数组和映射字面量: 可以用 const 声明编译时常量的数组和映射。
    const List<int> numbers = [1, 2, 3];
    const Map<String, int> scores = {'John': 100, 'Jane': 90};
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    继承关系
    dart有三种方式,分别是extends(继承),with(混入) ,implements(实现),三种可以混合使用,其中with,implements后可以多继承,用逗号隔开,extends后面只能跟一个,优先级顺序为with>extends>implements,当with,implements后跟了多个的时候,优先级最右边大于左边,依次类推,例如extends a with b,c implements d,h,优先级为c>b>a>h>d;

    函数可选参数
    与java不同,dart中不支持重载,java支持方法重载,dart想要实现java类似的效果,可以通过可选参数来实现

    selectFunction("张三");
    selectFunction("李四",type: 1);
    selectFunction("王五",type: 1,money: 83.2);
    
    void selectFunction(String name,{int? type,double? money}){
      print("名字:$name--类型:$type--金额:$money");
    }
    //注意dart可选参数必须要加?来表示该参数默认值为null,如果去掉?可以手动写个默认值,例如
    void selectFunction(String name,{int type = 0,double? money}){
      print("名字:$name--类型:$type--金额:$money");
    }
    //输出结果:名字:张三--类型:null--金额:null
    //名字:李四--类型:1--金额:null
    //名字:王五--类型:1--金额:83.2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    二.Flutter 中的一些常用Widget详解

    本文只是个别常用介绍,关于更多Widget的相关介绍看另一篇文章:Flutter 控件查阅清单

    Center(居中对齐小部件):

    Center小部件用于在可用空间内使其子小部件水平和垂直居中对齐。它接受一个需要居中的子小部件。Center小部件将扩展以填充父小部件的所有可用空间,并在该空间内居中其子小部件。

    Center(
      child: Text(
        'Hello, Flutter!',
        style: TextStyle(fontSize: 24.0),
      ),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Text(文本小部件):

    Text小部件用于在屏幕上显示一行文本。可以自定义文本的样式,例如字体大小、颜色和对齐方式。通过将字符串传递给Text小部件的data参数,可以设置文本的内容。

    常用的Text属性:

    • data(String):要显示的文本内容。
    • style(TextStyle):定义文本的样式,如字体、大小、颜色等。
    • textAlign(TextAlign):指定文本在水平方向上的对齐方式。
      –TextAlign.left:文本左对齐。
      –TextAlign.right:文本右对齐。
      –TextAlign.center:文本居中对齐。
      –TextAlign.justify:文本两端对齐,会调整单词和字之间的间隔。
    • textDirection(TextDirection):指定文本的方向,如从左到右或从右到左。
    • textScaleFactor(double):指定文本的缩放比例。
    • maxLines(int):指定允许的最大行数,超过将使用"…"截断。
    • overflow(TextOverflow):定义文本溢出时的处理方式。
    • softWrap(bool):指定文本是否自动换行。
     body: Center(
              child: Text(
                'Hello, Flutter!',
                style: TextStyle(
                  fontSize: 24,
                  fontWeight: FontWeight.bold,
                  color: Colors.blue,
                ),
              ),
            ),
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Button(按钮)

    RaisedButton 废弃

    ElevatedButton (代替RaisedButton)

    RaisedButton 是一个具有凸起效果的按钮,通常用于主要操作。

    它具有各种自定义属性,如 onPressed、child、color、disabledColor、textColor 等,以定制外观和行为。

    ElevatedButton(
      onPressed: () {
        // 处理按钮点击事件
      },
      child: Text('Click me'),
    )
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    FlatButton

    FlatButton 是一个扁平化的按钮,通常用于次要操作。

    它有类似于 RaisedButton 的自定义属性,可以根据需求进行定制。

    FlatButton(
      onPressed: () {
        // 按钮被点击时执行的操作
      },
      child: Text('Cancel'),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    OutlineButton

    OutlineButton 是一个带有边框的按钮,通常用于取消操作或与背景区分。

    它也有类似于 RaisedButton 的自定义属性,以便自定义外观和行为。

    OutlineButton(
      onPressed: () {
        // 按钮被点击时执行的操作
      },
      child: Text('Clear'),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    FloatingActionButton

    FloatingActionButton 是一个圆形的浮动操作按钮,常用于应用程序的主要操作。

    它也具有各种自定义属性和样式,可以根据需求进行调整。

    FloatingActionButton(
      onPressed: () {
        // 按钮被点击时执行的操作
      },
      child: Icon(Icons.add),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    IconButton

    IconButton 是一个只包含图标的按钮,通常用于具有图标表示的操作。

    它也有各种自定义属性和样式,以便自定义外观和行为。

    IconButton(
      onPressed: () {
        // 按钮被点击时执行的操作
      },
      icon: Icon(Icons.favorite),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Container(容器小部件):

    Container小部件是一个多用途灵活的小部件,可以包含其他小部件。允许自定义属性,如宽度、高度、填充、边距、颜色等,以控制其子小部件的布局和外观。它还可以对子小部件应用变换、装饰和约束。

    Container(
      width: 200.0,
      height: 100.0,
      color: Colors.blue,
      child: Center(
        child: Text(
          'Hello, Flutter!',
          style: TextStyle(fontSize: 24.0, color: Colors.white),
        ),
      ),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    RowColumn(行和列小部件):

    这些布局小部件用于将其子小部件按水平(Row)或垂直(Column)线排列。它们可以包含多个子小部件,并根据子小部件的属性和可用空间自动调整大小和位置。可以使用特定参数控制子小部件的对齐方式、间距和调整大小的行为。

    Row小部件具有以下一些常用的属性:

    • children(List:需要包含在Row中的子部件列表。
    • mainAxisAlignment(MainAxisAlignment):子部件在主轴方向上的对齐方式,默认是start。
    • crossAxisAlignment(CrossAxisAlignment):子部件在交叉轴方向上的对齐方式,默认是start。
    • mainAxisSize(MainAxisSize):Row在主轴方向上的大小约束,默认是MainAxisSize.max。
    • textDirection(TextDirection):子部件的文本方向,默认是TextDirection.ltr。
    • verticalDirection(VerticalDirection):子部件在垂直方向上布局的方向,默认是VerticalDirection.down。
     body: Row(
              mainAxisAlignment: MainAxisAlignment.center, // 在水平方向上居中对齐
              crossAxisAlignment: CrossAxisAlignment.start, // 在垂直方向上上对齐
              mainAxisSize: MainAxisSize.min, // 占用尽可能少的水平空间
              textDirection: TextDirection.ltr, // 子部件的文本方向从左到右
              verticalDirection: VerticalDirection.down, // 从上到下布局
              children: [
                Text(
                  'First Item',
                  style: TextStyle(fontSize: 24),
                ),
                SizedBox(width: 20), // 在子部件之间增加间距
                Text(
                  'Second Item',
                  style: TextStyle(fontSize: 24),
                ),
                Container(
                  color: Colors.blue,
                  width: 200,
                  height: 200,
                  child: Text(
                    'Third Item',
                    style: TextStyle(fontSize: 24, color: Colors.white),
                  ),
                ),
              ],
            ),
    
    • 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

    Column小部件具有以下一些常用的属性:

    • children(List:需要包含在Column中的子部件列表。
    • mainAxisAlignment(MainAxisAlignment):子部件在主轴方向上的对齐方式,默认是start。
    • crossAxisAlignment(CrossAxisAlignment):子部件在交叉轴方向上的对齐方式,默认是start。
    • mainAxisSize(MainAxisSize):Column在主轴方向上的大小约束,默认是MainAxisSize.max。
    • verticalDirection(VerticalDirection):子部件在垂直方向上布局的方向,默认是VerticalDirection.down。
    body: Column(
              mainAxisAlignment: MainAxisAlignment.center, // 在垂直方向上居中对齐
              crossAxisAlignment: CrossAxisAlignment.start, // 在水平方向上左对齐
              mainAxisSize: MainAxisSize.min, // 占用尽可能少的垂直空间
              verticalDirection: VerticalDirection.down, // 从上到下布局
              children: [
                Text(
                  'First Item',
                  style: TextStyle(fontSize: 24),
                ),
                SizedBox(height: 20), // 在子部件之间增加间距
                Text(
                  'Second Item',
                  style: TextStyle(fontSize: 24),
                ),
                Container(
                  color: Colors.blue,
                  width: 200,
                  height: 200,
                  child: Text(
                    'Third Item',
                    style: TextStyle(fontSize: 24, color: Colors.white),
                  ),
                ),
              ],
            ),
    
    • 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

    Image(图像小部件):

    Image小部件用于在屏幕上显示图像。它支持各种图像来源,例如本地资源、网络图像和内存图像。可以自定义其属性,如大小、缩放和对齐方式,以及处理加载和错误状态。

    Image(
      image: AssetImage('assets/images/flutter_logo.png'),
      width: 100.0,
      height: 100.0,
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    StatelessWidgetStatefulWidget

    StatelessWidget:
    StatelessWidget是一种无状态的小部件,意味着它在创建后是不可变的,不会随时间改变。它基于构建函数的输入参数,一旦构建完成,就渲染出静态的用户界面。简单来说,StatelessWidget没有内部状态(state)。

    import 'package:flutter/material.dart';
    
    class MyWidget extends StatelessWidget {
      final String text;
    
      MyWidget({required this.text});
    
      
      Widget build(BuildContext context) {
        return Container(
          child: Text(text),
        );
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    StatefulWidget:
    StatefulWidget是一种有状态的小部件,它的内部状态可以随时间变化,所以它可以在创建后重新构建。StatefulWidget由两个部分组成:一个是State对象,用于保存和管理小部件的状态,另一个是StatefulWidget类本身,用于构建小部件的UI。

    import 'package:flutter/material.dart';
    
    class CounterWidget extends StatefulWidget {
      
      _CounterWidgetState createState() => _CounterWidgetState();
    }
    
    class _CounterWidgetState extends State<CounterWidget> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      
      Widget build(BuildContext context) {
        return Column(
          children: [
            Text('Counter: $_counter'),
            ElevatedButton(
              onPressed: _incrementCounter,
              child: Text('Increment'),
            ),
          ],
        );
      }
    }
    
    
    • 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

    GestureDetector

    用于处理用户手势和触摸事件。它可以用于识别和响应各种手势,如点击、长按、拖动、缩放和滑动等。GestureDetector 可以包裹任何其他小部件,并通过回调函数来响应不同的手势事件。

    GestureDetector 的常用属性和介绍:

    • onTap: 当用户轻触手势时触发的回调函数。
    • onDoubleTap: 当用户双击手势时触发的回调函数。
    • onLongPress: 当用户长按手势时触发的回调函数。
    • onLongPressMoveUpdate: 当用户在长按手势的情况下移动时触发的回调函数。
    • onVerticalDragDown: 当用户在垂直方向开始拖动手势时触发的回调函数。
    • onVerticalDragEnd: 当用户在垂直方向结束拖动手势时触发的回调函数。
    • onScaleStart: 当用户开始缩放手势时触发的回调函数。
    • onScaleUpdate: 当用户进行缩放手势时触发的回调函数。
    • behavior: 用于指定如何识别和处理手势事件的 HitTestBehavior。

    使用示例:

    import 'package:flutter/material.dart';
    
    class MyGestureDetector extends StatelessWidget {
      
      Widget build(BuildContext context) {
        return GestureDetector(
          // 点击事件
          onTap: () {
            print('onTap');
          },
          // 双击事件
          onDoubleTap: () {
            print('onDoubleTap');
          },
          // 长按事件
          onLongPress: () {
            print('onLongPress');
          },
          // 缩放手势
          onScaleStart: (details) {
            print('onScaleStart: ${details.focalPoint}');
          },
          onScaleUpdate: (details) {
            print('onScaleUpdate: ${details.focalPoint}, ${details.scale}');
          },
          onScaleEnd: (details) {
            print('onScaleEnd: ${details.velocity}');
          },
          // 拖动手势
          onPanStart: (details) {
            print('onPanStart: ${details.globalPosition}');
          },
          onPanUpdate: (details) {
            print('onPanUpdate: ${details.globalPosition}');
          },
          onPanEnd: (details) {
            print('onPanEnd: ${details.velocity}');
          },
          // 指针击中测试
          behavior: HitTestBehavior.opaque,
          // 点击区域的命中测试
          hitTestBehavior: HitTestBehavior.translucent,
          // 排除特定手势
          excludeFromSemantics: true,
          // 双击事件的时间窗口
          doubleTapTimeout: Duration(milliseconds: 300),
          // 长按事件的时间窗口
          longPressTimeout: Duration(milliseconds: 500),
          // 长按事件的触发间隔
          longPressMoveUpdateDelay: Duration(milliseconds: 200),
          // 其它属性
          dragStartBehavior: DragStartBehavior.start,
          child: Container(
            width: 200,
            height: 200,
            color: Colors.blue,
          ),
        );
      }
    }
    
    
    • 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

    Stack

    Stack 是一个用于将多个小部件(Widgets)叠加在一起的布局小部件。Stack 允许您将小部件堆叠在其他小部件之上,这样可以创建各种复杂的布局,例如叠加式用户界面元素,重叠的图像和文本等。

    Stack 的主要特点和用法包括:

    1. 子部件的堆叠:Stack 可以包含多个子部件,它们会按照添加的顺序堆叠在一起。最后添加的子部件位于最上面。

    2. 定位子部件:通过 Positioned 小部件,您可以精确控制子部件在 Stack 中的位置。通过设置 left、top、right 和 bottom 属性,您可以指定子部件的左上角和右下角在 Stack 中的位置。

    3. 溢出处理:当子部件的大小超出 Stack 的边界时,您可以使用 overflow 属性来指定如何处理溢出内容。常见的选项包括 Overflow.clip(剪切超出边界的部分)和 Overflow.visible(允许子部件超出边界)。

    4. Alignment:您可以使用 alignment 属性来控制 Stack 中所有子部件的对齐方式。这会影响所有子部件的位置,除非子部件自身使用 Positioned 进行了具体定位。

    示例:

    Stack(
      alignment: Alignment.center, // 子部件的默认对齐方式
      children: <Widget>[
        Container(
          width: 200,
          height: 200,
          color: Colors.blue,
        ),
        Positioned(
          left: 50,
          top: 50,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.red,
          ),
        ),
        Positioned(
          right: 50,
          bottom: 50,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
          ),
        ),
      ],
    )
    
    
    • 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

    Align

    Align 是一个用于将单个子部件(Widget)相对于父部件进行对齐的小部件。Align 允许您精确控制子部件在父部件内的位置,并指定子部件在水平和垂直方向上的对齐方式。

    Align 小部件的主要属性包括:

    1. alignment:alignment 属性是 Alignment 类型的,用于指定子部件在父部件中的对齐方式。Alignment 使用 Alignment.x 和 Alignment.y 的值来表示水平和垂直方向上的对齐,它的取值范围是从 -1.0 到 1.0,其中 -1.0 表示左侧或顶部,1.0 表示右侧或底部,0.0 表示居中。

    2. child:child 属性用于指定要对齐的子部件。这是一个单一的小部件,通常是一个容器或其他UI元素。

    示例:

    Align(
      alignment: Alignment.center, // 将子部件居中对齐
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
        child: Text('Centered', style: TextStyle(color: Colors.white)),
      ),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    InkWell

    InkWell 的主要功能是在用户触摸屏幕时为其子项提供"涟漪"动画效果。这种涟漪效果是材料设计中的一个典型的触摸反馈,它可以给用户一个明确的视觉反馈,表示某个元素已经被触摸。

    除了涟漪动画效果,InkWell 还提供了一系列的回调函数,例如:

    • onTap: 用户轻触屏幕时触发。
    • onDoubleTap: 用户双击屏幕时触发。
    • onLongPress: 用户长按屏幕时触发。

    示例

    InkWell(
      onTap: () {
        print('InkWell tapped');
      },
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
        child: Center(
          child: Text('Tap Me'),
        ),
      ),
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    三.对齐 widgets

    mainAxisAlignmentcrossAxisAlignment是用于定位和对齐子部件的属性,它们通常用于Flex、Row和Column等布局小部件中。
    在这里插入图片描述
    mainAxisAlignment的值可以是以下之一:

    • MainAxisAlignment.start:将子部件沿主轴的起始位置对齐。
    • MainAxisAlignment.end:将子部件沿主轴的结束位置对齐。
    • MainAxisAlignment.center:将子部件沿主轴的中心位置对齐。
    • MainAxisAlignment.spaceBetween:将子部件均匀地分布在主轴上,使它们之间的间距相等,第一个子部件放置在起始位置,最后一个子部件放置在结束位置。
    • MainAxisAlignment.spaceAround:将子部件均匀地分布在主轴上,使它们之间和两端的间距相等。
    • MainAxisAlignment.spaceEvenly:将子部件均匀地分布在主轴上,使它们之间的间距和两端的间距相等。

    mainAxisAlignment使用示例:

    Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Container(color: Colors.red, width: 50, height: 50),
        Container(color: Colors.green, width: 50, height: 50),
        Container(color: Colors.blue, width: 50, height: 50),
      ],
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    crossAxisAlignment的值可以是以下之一:

    • CrossAxisAlignment.start:将子部件沿副轴的起始位置对齐。
    • CrossAxisAlignment.end:将子部件沿副轴的结束位置对齐。
    • CrossAxisAlignment.center:将子部件沿副轴的中心位置对齐。
    • CrossAxisAlignment.stretch:将子部件沿副轴拉伸以填充可用空间。
    • CrossAxisAlignment.baseline:将子部件的基线与副轴上的基准线对齐,需要在子部件上设置基线对齐方式(如TextBaseline)。

    crossAxisAlignment使用示例:

    Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Container(color: Colors.red, width: 50, height: 50),
        Container(color: Colors.green, width: 50, height: 50),
        Container(color: Colors.blue, width: 50, height: 50),
      ],
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    四.调整widgets大小

    Expanded widget
    用于在父部件的剩余可用空间中扩展一个子部件。它通常与Flex、Column或Row等灵活的布局小部件一起使用,以便在父部件中使用弹性盒子模型进行布局。

    当Expanded小部件包装在一个子部件周围时,它会将该子部件填充并扩展到可用空间的剩余部分,以沿着主轴方向占据所有剩余的空间。这使得子部件能够灵活地从父部件中分配和占据可用空间,而不受其自身固定大小的限制。

    使用示例

    Row(
      children: [
        Container(color: Colors.red, width: 50, height: 50),
        Expanded(
          child: Container(color: Colors.green),
        ),
        Container(color: Colors.blue, width: 50, height: 50),
      ],
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Flex
    Flex用于创建灵活的布局,可以根据可用空间的大小动态调整子部件的大小。可以将 Flex 小部件作为Expanded的子部件,并通过指定flex属性来控制子部件在可用空间中的分配比例。
    可以简单理解为LinearLayout中的权重

    使用示例

    Row(
      children: [
        Container(color: Colors.red, width: 50, height: 50),
        Expanded(
          flex: 2,
          child: Container(color: Colors.green),
        ),
        Expanded(
          flex: 1,
          child: Container(color: Colors.blue),
        ),
      ],
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    当一个Expanded组件包含在一个垂直方向(或水平方向)的Flex容器(如Column或Row)中时,该Expanded组件会将其子组件填充到相应方向上的所有可用空间。如果有多个垂直方向的Expanded组件,则它们会按照它们的flex属性(默认为1)来分配可用空间。

    换句话说,Expanded组件在默认情况下会尽可能地扩展,以填充Flex容器中剩余的可用空间,但具体的高度取决于Flex容器的大小和其他子组件的约束条件

    五.通用布局 widgets

    标准 widgets

    • Container:向 widget 增加 padding、margins、borders、background color 或者其他的“装饰”。

    • GridView:将 widget 展示为一个可滚动的网格。

    • ListView:将 widget 展示为一个可滚动的列表。

    • Stack:将 widget 覆盖在另一个的上面。

    Material widgets

    • Card:将相关信息整理到一个有圆角和阴影的盒子中。

    • ListTile:将最多三行的文本、可选的导语以及后面的图标组织在一行中。


    六.输入表单

    TextField (文本框)

    用于接收用户输入文本的小部件,它提供了一个可编辑的文本框,用户可以在其中输入、编辑和选择文本。

    常用的属性及其作用:

    1. controller: 一个 TextEditingController 对象,用于控制文本输入框的值,获取输入的内容或设置初始值。
    2. focusNode: 一个 FocusNode 对象,用于管理输入框的焦点。
    3. decoration: InputDecoration 类型的对象,用于定义输入框的外观,包括标签文本、提示文本、边框样式等。
    4. keyboardType: TextInputType 枚举类型,指定键盘的类型,以匹配输入的预期内容,如文本、数字、URL、电子邮件等。
    5. textInputAction: TextInputAction 枚举类型,定义了与输入框关联的操作按钮的行为,如完成、下一步、搜索等。
    6. onChanged: 输入内容变化时的回调函数,接受最新的输入值作为参数,通常用于实时校验或更新状态。
    7. onSubmitted: 用户提交输入后的回调函数,接受最终的输入值作为参数。
    8. obscureText: bool 值,用于指定是否要隐藏输入内容,常用于密码输入框。
    9. maxLines: int 值,用于指定输入框的最大行数。
    10. maxLength: int 值,用于指定最大输入长度。
    11. enabled: bool 值,用于指定输入框是否可编辑。
    12. autofocus: bool 值,用于指定是否自动获取焦点。
    13. textAlign: TextAlign 枚举类型,指定文本内容的对齐方式,如左对齐、右对齐、居中等。
    14. cursorColor: Color 对象,指定光标的颜色。
    15. cursorWidth: double 值,用于指定光标的宽度。

    使用示例:

    import 'package:flutter/material.dart';
    
    class MyTextField extends StatefulWidget {
      
      _MyTextFieldState createState() => _MyTextFieldState();
    }
    
    class _MyTextFieldState extends State<MyTextField> {
      TextEditingController _controller = TextEditingController();
      FocusNode _focusNode = FocusNode();
    
      
      void dispose() {
        _controller.dispose();
        _focusNode.dispose();
        super.dispose();
      }
    
      
      Widget build(BuildContext context) {
        return TextField(
          controller: _controller,
          focusNode: _focusNode,
          decoration: InputDecoration(
            labelText: 'Enter your name',
            hintText: 'John Doe',
            prefixIcon: Icon(Icons.person),
            suffixIcon: IconButton(
              icon: Icon(Icons.clear),
              onPressed: () {
                _controller.clear();
              },
            ),
            border: OutlineInputBorder(),
          ),
          keyboardType: TextInputType.text,
          textInputAction: TextInputAction.done,
          onChanged: (value) {
            print('Input: $value');
          },
          onSubmitted: (value) {
            print('Submitted: $value');
            _focusNode.unfocus();
          },
        );
      }
    }
    
    
    • 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

    关于TextEditingController和FocusNode的介绍:

    TextEditingController
    TextEditingController是一个控制文本输入的类,它提供了一些方法和属性来获取和修改TextField中输入的文本。主要作用包括:

    • 可以获取TextField中的文本内容:使用text属性可以获取TextField中当前的文本内容。
    • 可以设置TextField的初始值或修改文本内容:使用text属性可以设置TextField的初始值,也可以通过textEditingController.text = newText来修改文本内容。
    • 可以监听文本变化:可以通过注册addListener()方法来监听TextField中的文本变化,以便执行特定的操作。

    FocusNode
    FocusNode是用于处理TextField焦点的类,它允许管理应用程序中的焦点,并监听焦点变化事件。主要作用包括:

    • 管理TextField的焦点:通过将TextField的focusNode属性设置为FocusNode对象,可以管理TextField的焦点。例如,可以使用focusNode.requestFocus()请求焦点,并使用focusNode.unfocus()取消焦点。
    • 监听焦点变化:可以通过注册addListener()方法来监听焦点的变化,以便在焦点状态发生变化时执行特定的操作,比如显示或隐藏键盘。
    • 控制键盘行为:通过设置keyboardType和textInputAction属性,可以控制键盘的类型(例如纯文本、数字等)和键盘完成按钮的样式(例如完成、下一个等)。

    TextFormField (表单文本框)

    TextFormField 是一个带有表单功能的文本输入字段小部件。它是基于 TextField 的封装,并提供了一些额外的功能,如表单验证和错误处理。

    常用属性及其作用:

    1. controller: 一个 TextEditingController 对象,用于控制文本输入框的值,获取输入的内容或设置初始值。

    2. focusNode: 一个 FocusNode 对象,用于管理输入框的焦点。

    3. decoration: InputDecoration 类型的对象,用于定义输入框的外观,包括标签文本、提示文本、边框样式等。

    4. keyboardType: TextInputType 枚举类型,指定键盘的类型,以匹配输入的预期内容,如文本、数字、URL、电子邮件等。

    5. textInputAction: TextInputAction 枚举类型,定义了与输入框关联的操作按钮的行为,如完成、下一步、搜索等。

    6. validator: 一个函数,接受输入的字符串,根据需求返回一个错误提示字符串,用于对输入内容进行验证。

    7. onChanged: 输入内容变化时的回调函数,接受最新的输入值作为参数,通常用于实时校验或更新状态。

    8. onFieldSubmitted: 用户提交输入后的回调函数,接受最终的输入值作为参数。

    使用示例:

    import 'package:flutter/material.dart';
    
    class MyForm extends StatefulWidget {
      
      _MyFormState createState() => _MyFormState();
    }
    
    class _MyFormState extends State<MyForm> {
      final _formKey = GlobalKey<FormState>();
      TextEditingController _nameController = TextEditingController();
      
      
      Widget build(BuildContext context) {
        return Form(
          key: _formKey,
          child: TextFormField(
            controller: _nameController,
            decoration: InputDecoration(
              labelText: 'Name',
              hintText: 'Enter your name',
            ),
            validator: (value) {
              if (value.isEmpty) {
                return 'Please enter your name';
              }
              return null;
            },
            onFieldSubmitted: (value) {
              if (_formKey.currentState.validate()) {
                // 执行提交操作
              }
            },
          ),
        );
      }
    }
    
    
    • 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

    七.关键词

    part

    用于将多个Dart文件组织在一起,以便更好地管理和维护代码。

    part 指令是Dart语言的一部分,它允许你将一个Dart文件分成多个部分,并将它们组合在一起以形成一个完整的库。这对于将大型代码库分解为更小的可管理部分非常有用。

    part ‘WeiBoCommentList.g.dart’; 表示当前的Dart文件是一个库的一部分,并且需要引入另一个名为 WeiBoCommentList.g.dart 的Dart文件,以共享一些代码或声明。

    通常,part 指令在使用代码生成工具时非常有用,例如json_serializable或moor_generator。这些工具可以根据模型类自动生成代码,而将生成的代码放在单独的文件中,然后使用 part 指令将其引入到主要的模型文件中。

    例如,假设 WeiBoCommentList.g.dart 包含自动生成的序列化或数据库访问代码,而 WeiBoCommentList.dart 包含模型类的定义。通过使用 part 指令,你可以将自动生成的代码与手动编写的代码分离开来,以便更轻松地维护和管理项目。

    Completer

    Completer 是一个用于处理异步操作的类,它允许你手动控制异步操作的完成和结果返回。Completer 的主要作用是创建一个 Future 对象,并允许你在某个后续时刻手动完成这个 Future,从而传递一个值或错误。

    以下是 Completer 的主要作用:

    1. 手动完成 Future:使用 Completer,你可以创建一个未来的实例,并在需要的时候手动完成它。这对于异步操作,如网络请求、文件读写等,非常有用,因为你可以在操作完成后通过 Completer 将结果传递给等待的代码。

    2. 处理异步操作的结果:当你使用异步操作时,通常需要等待操作完成并获取结果。通过 Completer 创建的 Future,你可以使用 await 关键字或 .then() 方法等方式来等待操作完成,并获取其结果。

    示例:

    import 'dart:async';
    
    Future<void> fetchData() async {
      Completer<void> completer = Completer<void>();
    
      // 模拟一个异步操作,等待2秒钟后完成
      Future.delayed(Duration(seconds: 2), () {
        completer.complete(); // 手动完成Future
      });
    
      await completer.future; // 等待Future完成
    
      print('Data fetched successfully');
    }
    
    void main() {
      fetchData();
      print('Fetching data...'); // 这一行会在异步操作完成前执行
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    StreamSubscription

    StreamSubscription 是使用 Dart 中的流(Stream)的一种方式。流是一系列异步事件的序列,可以用于接收和处理来自异步操作(如网络请求、数据库查询等)的事件。

    StreamSubscription 用于订阅流,并可以跟踪和取消订阅。当你订阅一个流时,你可以指定一个回调函数来处理流中发出的事件。回调函数会在每个事件到达时被调用,而不是等待整个流完成。

    订阅流

    要订阅流,首先需要获取一个流对象。在Flutter中,很多类(如StreamController、StreamTransformer等)都提供了流的实例化和管理。一旦获取到流对象,你可以使用stream.listen()方法订阅流,并提供一个回调函数来处理流中的事件。

    Stream<int> countStream() async* {
      for (int i = 1; i <= 5; i++) {
        await Future.delayed(Duration(seconds: 1));
        yield i;
      }
    }
    
    void main() {
      final stream = countStream();
      final subscription = stream.listen((data) {
        print('Received: $data');
      });
    
      // 取消订阅
      subscription.cancel();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    上面的示例中,创建了一个简单的计数流countStream(),它每隔一秒产生一个整数。我们通过stream.listen()方法订阅了这个流,并提供了一个回调函数来处理每个事件。

    取消订阅

    当不再需要订阅流时,应该显式地取消订阅,以释放资源和停止事件的处理。可以调用StreamSubscription对象的cancel()方法来取消订阅。

    final subscription = stream.listen((data) {
      print('Received: $data');
    });
    
    // 取消订阅
    subscription.cancel();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在上面的示例中,保存了StreamSubscription对象到subscription变量中,并在不再需要时调用了cancel()方法来取消订阅。

    使用StreamSubscription的其他方法和属性

    StreamSubscription提供了一些其他有用的方法和属性,用于管理订阅和检查流的状态,例如:

    • pause()resume():暂停和恢复订阅,以便控制事件的处理。
    • onData():设置一个新的事件回调函数,替换原来的回调函数。
    • onError():设置一个错误回调函数,用于处理流中的错误事件。
    • onDone():设置一个完成回调函数,用于处理流结束时的事件。
    • isPaused:一个布尔值,表示当前订阅是否已暂停。

    mixin

    Mixin是一种强大的代码重用机制,它允许你将一个类的成员添加到另一个类中,而无需继承该类。Mixin提供了一种方式来在类之间共享代码,同时保持类之间的分离性。

    1. 基本语法
    class MyClass with MyMixin {
      // 类的成员和方法
    }
    
    mixin MyMixin {
      // Mixin中的成员和方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在上面的代码中,MyClass类通过with MyMixin语法引入了MyMixin的功能。

    2. Mixin的特点
    • Mixin类本身不能被实例化,它们只能被用作其他类的组成部分。
    • 类可以使用多个Mixin,通过逗号分隔,这允许多个类的功能被组合到一个类中。
    • Mixin可以有自己的属性和方法,这些属性和方法可以被包含Mixin的类访问和使用。
    • 如果多个Mixin中有同名的方法或属性,那么包含Mixin的类必须通过显式指定使用哪个Mixin的方式来解决冲突。
    • Mixin的顺序很重要,因为方法冲突时会按照Mixin的顺序来解析。
    3. Mixin的应用场景
    3.1. 接口实现

    Mixin可以用于实现接口,允许一个类同时具有多个接口的功能。

    class MyWidget with WidgetMixin, ClickableMixin {
      // ...
    }
    
    • 1
    • 2
    • 3
    3.2. 功能复用

    Mixin可以用于将通用功能添加到多个类中,避免重复编写相似的代码。

    mixin LoggerMixin {
      void log(String message) {
        print(message);
      }
    }
    
    class MyClass with LoggerMixin {
      // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.3. 数据序列化与反序列化

    Mixin可以用于为多个数据模型类添加数据序列化和反序列化的功能。

    mixin JsonSerializable {
      Map<String, dynamic> toJson();
      void fromJson(Map<String, dynamic> json);
    }
    
    class Person with JsonSerializable {
      // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    3.4. 路由导航

    在Flutter中,Mixin经常用于处理路由导航,以减少页面之间的代码冗余。

    3.5. 状态管理

    在Flutter中,StatefulWidget常常使用Mixin来添加状态管理的功能。

    with

    with关键字用于在类定义中混入(mixin)一个或多个 mixin 类。Mixin 是一种在 Dart 中实现代码重用的机制,它允许你将一个或多个 mixin 类的特性添加到一个类中,而无需继承这些 mixin 类。

    使用方式:

    class MyClass with Mixin1, Mixin2, ... {
      // 类的成员和方法
    }
    
    • 1
    • 2
    • 3

    关于 with 关键字的详细介绍:

    1. 混入Mixin的类:with 后面可以跟一个或多个 mixin 类,用逗号分隔。这意味着你可以从多个 mixin 类中继承特性,将它们组合到一个类中,从而实现多重继承的效果。

    2. Mixin的顺序:Mixin 的顺序很重要,因为如果多个 mixin 类中具有相同名称的属性或方法,类中将使用最后一个 mixin 中定义的属性或方法。这个规则确保了 mixin 类的顺序对类的行为产生影响。

    3. Mixin的特性:通过使用 with 关键字,类将继承 mixin 类的属性、方法和功能,这些特性会被添加到类中。这允许你在不继承 mixin 类的情况下,使用 mixin 类的功能。

    4. Mixin的用途:with 关键字通常用于以下情况:

    • 实现接口:通过混入一个 mixin 类,类可以实现多个接口的功能。
    • 代码复用:可以将通用功能添加到多个类中,以减少代码重复性。
    • 实现混合功能:在不使用多重继承的情况下,将多个 mixin 类的功能组合在一个类中。

    dynamic和Object

    1、Object 是dart所有对象的根基类,也就是说所有类型都是Object的子类,所以任何类型的数据都可以赋值给Object声明的对象.
    2、dynamic与var一样都是关键词,声明的变量可以赋值任意对象. 而dynamic与Object相同之处在于,他们声明的变量可以在后期改变赋值类型.

    typedef

    用于创建自定义类型别名(type alias)。类型别名允许你为现有的数据类型或函数签名定义一个新的名称,以便在代码中更清晰地表达类型或函数签名的含义

    以下是关于typedef关键字的详细介绍:

    1. 为数据类型创建类型别名:
    typedef IntList = List<int>;
    typedef StringMap = Map<String, String>;
    
    
    • 1
    • 2
    • 3
    1. 为函数签名创建类型别名:
      对于回调函数或函数参数特别有用
    typedef VoidCallback = void Function();
    typedef BinaryOperation = int Function(int, int);
    
    
    • 1
    • 2
    • 3
    1. 与高阶函数一起使用:
    typedef FilterFunction<T> = bool Function(T);
    
    List<T> filterList<T>(List<T> list, FilterFunction<T> filter) {
      return list.where(filter).toList();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    get

    get关键字用于创建一个Getter方法,它允许你访问对象的属性或计算属性的值,就像访问类的实例变量一样。Getter方法通常用于获取对象的某个属性值,而不是直接访问实例变量,以提供更多的封装和控制。

    1.创建Getter方法:通过在类中定义一个以get关键字开头的方法,你可以创建一个Getter方法,该方法用于获取某个属性的值。Getter方法的语法如下:

    Type get propertyName {
      // 在这里计算和返回属性的值
    }
    
    • 1
    • 2
    • 3

    其中,Type是属性的数据类型,propertyName是你希望暴露的属性名称。

    2.延迟加载属性:Getter方法可以用于延迟加载属性的值。这意味着属性的值只有在首次访问Getter方法时才会计算,而不是在对象创建时。这对于节省资源和提高性能很有用。

    class LazyLoader {
      List<int> _data = [1, 2, 3, 4];
    
      int get sum {
        // 计算并返回列表元素的总和
        return _data.reduce((a, b) => a + b);
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.属性访问控制:使用Getter方法可以对属性的访问进行控制,例如,你可以在Getter方法中添加条件来检查属性的有效性,然后返回相应的值。

    class Temperature {
      double _celsius;
    
      Temperature(this._celsius);
    
      double get celsius {
        if (_celsius < -273.15) {
          throw ArgumentError("Temperature cannot be below absolute zero.");
        }
        return _celsius;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.在子类中覆盖:Getter方法可以在子类中被覆盖,允许你根据需要自定义子类的属性访问行为。

    class Parent {
      int get value => 42;
    }
    
    class Child extends Parent {
      
      int get value => super.value * 2; // 在子类中覆盖Getter方法
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    async await Future

    async 用于表示某个函数是一个异步函数,它可以执行异步操作而不会阻塞应用程序的主线程。异步操作通常包括网络请求、文件读写、定时器等需要等待一段时间才能完成的任务。

    async的详细介绍:

    1. 异步函数声明: 要声明一个异步函数,只需在函数声明前加上async关键字。例如:
    Future<void> fetchData() async {
      // 异步操作的代码
    }
    
    • 1
    • 2
    • 3

    这个函数是一个异步函数,它返回一个Future,表示它将在未来某个时间点完成。

    1. await关键字: 在异步函数中,可以使用await关键字来等待其他异步操作完成,而不会阻塞当前函数的执行。例如:
    Future<void> fetchData() async {
      var result = await fetchSomeDataFromNetwork();
      // 在fetchSomeDataFromNetwork完成后,继续执行后续代码
    }
    
    • 1
    • 2
    • 3
    • 4

    在这个示例中,await会等待fetchSomeDataFromNetwork函数完成,并且只有在该函数完成后才会继续执行后续代码。

    1. Future对象: 异步函数通常返回一个Future对象,表示异步操作的结果或状态。Future对象可以有不同的泛型类型,例如Future表示一个将来会返回整数结果的Future。您可以使用Future对象来处理异步操作的成功和失败,以及获取异步操作的结果。
    Future<void> fetchData() async {
      try {
        var result = await fetchSomeDataFromNetwork();
        // 处理成功的结果
      } catch (error) {
        // 处理发生错误的情况
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 错误处理: 在异步操作中,错误处理至关重要。可以使用try-catch块来捕获可能出现的异常,并处理它们。上面的示例中就包括了一个try-catch块,以处理可能在fetchSomeDataFromNetwork中抛出的错误

    2. 并发异步操作: 在Flutter中,可以同时运行多个异步操作,并等待它们全部完成,可以通过Future.wait函数来实现。这对于同时发起多个网络请求或执行多个并行任务非常有用。

    Future<void> fetchMultipleData() async {
      var result1 = fetchSomeDataFromNetwork1();
      var result2 = fetchSomeDataFromNetwork2();
      
      // 等待多个异步操作完成
      await Future.wait([result1, result2]);
      
      // 继续执行后续代码
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    未完待续…

  • 相关阅读:
    Linux 系统监控与性能调优
    SRE运维和DevOps之间是什么关系?
    1496. 判断路径是否相交
    南王科技IPO过会:年营收12亿 华莱士关联方持有近28%股权
    java计算机毕业设计ssm+vue青年志愿者社团管理系统
    MySQL练习题
    1006 Sign In and Sign Out
    C# 入坑JAVA 潜规则 大小写敏感文件名和类名 枚举等 入门系列2
    应用层如何感知传输层链路故障
    (二十二)mmdetection源码解读:faster_rcnn_r50_fpn.py详解roi_head
  • 原文地址:https://blog.csdn.net/WriteBug001/article/details/132837767