带你阅读 Flutter Demo(flutter 保姆级入门教程)

news2024/10/2 14:26:09
dart、flutter
Flutter Demo 解析

- 文章信息 - Author: Jack Lee (jcLee95)
Visit me at: https://jclee95.blog.csdn.net
Email: 291148484@163.com.
Shenzhen Chine
Address of this article:https://blog.csdn.net/qq_28550263/article/details/xxxxxx

【介绍】:本文带你阅读 Flutter Demo,并全面解析其中涉及的相关知识点。

【提示】:效果演示在本文末尾


1. 概述

2. 第一部分:Material 导入 和主函数

2.1 看代码

这部分代码为:

import 'package:flutter/material.dart';

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

2.2 导入 Material

import 'package:flutter/material.dart';

这行代码导入了 Flutter 的 Material 库,它提供了大量的预定义 UI 组件和样式,使我们能够快速构建具有 Material Design 风格的应用程序。

2.2 main函数

程序入口

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

main() 函数是 Dart 程序的入口点。在这个函数中,我们调用了 runApp() 方法并传递了一个 MyApp 类的常量实例。runApp() 方法将传入的 Widget(组件)作为应用程序的根 Widget,并开始构建 Widget 树。在这里,我们将自定义的 MyApp Widget 作为应用程序的根 Widget

runApp 函数

runApp() 函数是 Flutter 应用程序的启动函数。它接受一个 Widget 参数,作为应用程序的根 Widget。当调用 runApp() 函数时,Flutter 会将传入的 Widget 附加到渲染树中,并开始构建和显示整个 Widget 树。这个函数通常在应用程序的 main() 函数中调用,以便在应用程序启动时执行。

runApp() 函数的相关信息如下:

项目描述
参数runApp() 函数接受一个 Widget 参数,这个 Widget 通常是一个自定义的根 Widget,它包含了应用程序的整个 UI 结构。
功能runApp() 函数将传入的 Widget 作为根 Widget,附加到渲染树中。接着,Flutter 开始构建和显示整个 Widget 树,从根 Widget 开始,逐级向下构建各个子 Widget
用法runApp() 函数通常在应用程序的 main() 函数中调用,以便在应用程序启动时执行。

例如:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Hello World')),
        body: Center(child: Text('Welcome to my app!')),
      ),
    );
  }
}

在这个示例中,runApp() 函数在 main() 函数中被调用,并传入了一个 MyApp 类的实例。MyApp 是一个自定义的根 Widget,包含了整个应用程序的 UI 结构。

3. 第二部分:无状态组件 MyApp 类

3.1 看代码

这部分代码为:

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // 这个 widget 是您应用程序的根。
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // 这是您应用程序的主题。
        //
        // 尝试一下:尝试使用 "flutter run" 运行您的应用程序。您会看到
        // 应用程序具有蓝色的工具栏。然后,在不退出应用的情况下,
        // 尝试将下面 colorScheme 中的 seedColor 更改为 Colors.green,
        // 然后调用 "hot reload"(保存更改或按下 Flutter 支持的 IDE 中的 "hot
        // reload" 按钮,或者如果您使用了命令行启动应用程序,则按 "r")。
        //
        // 注意计数器没有重置为零;应用程序状态在重新加载期间不会丢失。
        // 要重置状态,请使用热重启代替。
        //
        // 这对代码也同样适用,而不仅仅是值:大多数代码更改都可以
        // 通过热重载进行测试。
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter演示主页'),
    );
  }
}

3.2 继承 StatelessWidget 类

以下是对 Flutter 代码的解析:

class MyApp extends StatelessWidget {
  const MyApp({super.key});

这段代码定义了一个名为 MyApp 的类,该类继承自 StatelessWidgetStatelessWidget 是一个不可变的 Widget,它描述了应用程序的一部分 UI。MyApp 类有一个构造函数,它接受一个名为 key 的可选参数,并将其传递给父类 StatelessWidget 的构造函数。

3.3 StatelessWidget 类的 build 方法

  
  Widget build(BuildContext context) {

这里我们覆盖了 StatelessWidget 类中的 build 方法。build 方法是一个返回 Widget 的函数,它接受一个 BuildContext 参数。BuildContext 是一个表示当前 Widget 在 Widget 树中的位置的对象。当 Flutter 需要构建这个 Widget 时,会调用这个方法。

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter演示主页'),
    );
  }
}

build 方法中,我们返回一个 MaterialApp Widget。MaterialApp 是一个方便的顶级 Widget,它包含了许多 Material Design 风格的应用程序所需的基本组件。它接受以下参数:

  • title:应用程序的标题,通常用于任务管理器或窗口标题。

  • theme:应用程序的主题数据。在这里,我们使用 ThemeData 类来创建一个自定义主题,其中:

    • colorScheme:使用 ColorScheme.fromSeed() 方法生成一个基于 Colors.deepPurple 的颜色方案。
    • useMaterial3:设置为 true,以便在应用程序中使用 Material 3 风格。
  • home:应用程序的主屏幕 Widget。在这里,我们创建了一个名为 MyHomePage 的自定义 Widget,并设置了其标题为 “Flutter演示主页”。

StatelessWidget 类中,build 方法是一个描述由该 Widget 表示的用户界面部分的方法。它通过构建其他 Widget 的组合来描述用户界面,这些 Widget 以更具体的方式描述用户界面。构建过程会递归进行,直到用户界面的描述完全具体化。框架会在将此 Widget 插入到给定的 BuildContext 中以及此 Widget 的依赖关系发生更改(例如,此 Widget 引用的 InheritedWidget 发生更改)时调用此方法。

在实践中,build 方法的主要作用是返回一个新的 Widget,该 Widget 描述了应用程序的用户界面。通常,这个方法会包含一些条件逻辑,以便根据传入的参数或外部状态生成不同的 Widget。这使得 StatelessWidget 成为一个非常灵活的构建块,可以用来创建复杂的用户界面。


Widget build(BuildContext context) {
  // 在此处返回一个新的 Widget,描述应用程序的用户界面。
}

3.4 Dart 语言中的 @override 注解

关于 dart 语言的注解,可以参考博文《Dart笔记:Dart语言中的注解》

@override注解用于表示子类的方法覆盖了父类的方法。这有助于在重构代码时确保正确地覆盖了父类方法。如果没有正确覆盖,Dart分析器会发出警告。

3.5 MaterialApp 顶层组件

MaterialApp 是一个方便的顶级 Widget,它封装了一些 Material Design 风格的应用程序所需的基本组件,如导航、主题和路由。它继承自 WidgetsApp 类,提供了一些与 Material Design 相关的功能。以下是 MaterialApp 的一些主要属性及其解释:

属性类型默认值描述参考链接
titleString‘’应用程序的标题,将显示在操作系统的任务切换器中。MaterialApp.title
homeWidgetnull应用程序的默认页面,通常是显示在应用程序启动时的第一个页面。MaterialApp.home
themeThemeDatanull应用程序的全局主题。您可以定义自己的 ThemeData 对象,以自定义应用程序的颜色、字体、按钮样式等。MaterialApp.theme
colorColornull应用程序在操作系统界面中使用的主色,如 Android 的任务切换器。如果未设置,则使用 ThemeData.primaryColorMaterialApp.color
routesMap<String, WidgetBuilder>null应用程序的路由表,用于定义应用程序中的页面导航。路由表是一个字符串到 WidgetBuilder 的映射,其中字符串表示路由名称,WidgetBuilder 是一个接受 BuildContext 并返回 Widget 的函数。MaterialApp.routes
initialRouteStringnull应用程序的初始路由名称。如果设置了 initialRoute,则在启动时将导航至该路由,而不是使用 home 属性。MaterialApp.initialRoute
onGenerateRouteRouteFactorynull一个回调函数,用于根据给定的路由设置生成路由。如果您需要在应用程序中使用动态路由或参数化路由,可以使用此属性。MaterialApp.onGenerateRoute
onUnknownRouteRouteFactorynull一个回调函数,用于处理未在 routes 表中找到的路由。通常用于显示一个 “404 页面未找到” 的错误页面。MaterialApp.onUnknownRoute
navigatorKeyGlobalKey<NavigatorState>null与应用程序的 Navigator 相关联的全局键。如果您需要从应用程序的其他部分访问 Navigator,可以使用此属性。MaterialApp.navigatorKey
builderTransitionBuildernull一个回调函数,可以在应用程序的路由之上插入一个 Widget。这对于需要在整个应用程序范围内显示的 Widget(如对话框或覆盖层)非常有用。MaterialApp.builder
localizationsDelegatesList<LocalizationsDelegate<dynamic>>null一个 LocalizationsDelegate 列表,用于设置应用程序的本地化资源。MaterialApp.localizationsDelegates
supportedLocalesList<Locale>null应用程序支持的地区列表。MaterialApp.supportedLocales

以下是一个简单的 MaterialApp 示例:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyHomePage(),
    );
  }
}

3.6 色彩方案:ColorScheme 类

官方文档位于:https://api.flutter.dev/flutter/material/ColorScheme-class.html

ColorScheme 是一个包含一组用于描述应用程序颜色的属性的类。它是一个不可变的对象,用于定义应用程序中使用的颜色。在 Material Design 中,ColorScheme 用于定义主题的颜色。以下是 ColorScheme 的一些常用属性:

属性描述
primary应用程序主要部分的背景颜色。例如,工具栏和浮动操作按钮。
primaryVariant主要颜色的较暗版本。
secondary应用程序次要部分的背景颜色。例如,选项卡栏。
secondaryVariant次要颜色的较暗版本。
surface卡片和抽屉等表面元素的背景颜色。
background应用程序背景颜色。
error错误状态和异常情况下使用的颜色。
onPrimary显示在主要颜色上的文本和图标的颜色。
onSecondary显示在次要颜色上的文本和图标的颜色。
onSurface显示在表面颜色上的文本和图标的颜色。
onBackground显示在背景颜色上的文本和图标的颜色。
onError显示在错误颜色上的文本和图标的颜色。
brightness应用程序的整体亮度。它是一个 Brightness 枚举,可以是 Brightness.lightBrightness.dark

例如:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ColorScheme Demo',
      theme: ThemeData(
        colorScheme: ColorScheme(
          primary: Colors.blue,
          primaryVariant: Colors.blue[700],
          secondary: Colors.orange,
          secondaryVariant: Colors.orange[700],
          surface: Colors.white,
          background: Colors.white,
          error: Colors.red,
          onPrimary: Colors.white,
          onSecondary: Colors.white,
          onSurface: Colors.black,
          onBackground: Colors.black,
          onError: Colors.white,
          brightness: Brightness.light,
        ),
      ),
      home: MyHomePage(),
    );
  }
}

4. 第三部分:有状态组件 MyHomePage

4.1 看代码

这部分代码如下:

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  // 这个 widget 是你的应用程序的主页。它是有状态的,这意味着它有一个 State 对象
  // (在下面定义),其中包含影响其外观的字段。

  // 这个类是 state 的配置。它保存了由父级(在本例中是 App widget)提供的值
  // (在本例中是标题),并被 State 的 build 方法使用。Widget 子类中的字段总是
  // 被标记为 "final"。

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

4.2 继承于 StatefulWidget 类

这段代码定义了一个名为 MyHomePageStatefulWidget 类,表示该类为一个 有状态组件

class MyHomePage extends StatefulWidget {

这一行定义了一个名为 MyHomePage 的类,它继承自 StatefulWidgetStatefulWidget 是 Flutter 中的一种 Widget,它可以在其生命周期内保持可变状态。

const MyHomePage({super.key, required this.title});

这是 MyHomePage 类的构造函数。它接受两个参数:

  • super.key:这是传递给父类(StatefulWidget)构造函数的可选 key 参数。key 参数用于控制框架如何将新的 Widget 与先前的 Widget 关联起来。通常情况下,您不需要处理 key,除非您在处理有状态的 Widget 或需要对 Widget 树进行优化。
  • required this.title:这是一个必需的 title 参数,它是一个字符串。required 关键字表示调用构造函数时必须提供此参数。this.title 表示将传入的参数值赋给类的 title 属性。

4.3 title 属性

final String title;

这一行定义了一个名为 title 的不可变字符串属性。final 关键字表示一旦初始化后,这个属性将无法更改。

4.4 createState 方法

  
  State<MyHomePage> createState() => _MyHomePageState();

这是 createState 方法,它是 StatefulWidget 类的必需方法。此方法用于创建与此 StatefulWidget 实例关联的状态对象。@override 关键字表示我们在这里重写了父类的方法。State<MyHomePage> createState() => _MyHomePageState(); 表示我们将返回一个名为 _MyHomePageState 的新状态对象。

createState 方法是 StatefulWidget 类的核心方法,它用于创建与 StatefulWidget 实例关联的状态对象。当框架需要构建 StatefulWidget 时,它会调用此方法以创建一个新的状态对象。这个状态对象将在 StatefulWidget 的整个生命周期中保持与之关联。

  • @override:这是一个元数据注解,表示我们将重写父类 StatefulWidget 的方法。在这种情况下,我们重写 createState 方法。这样做的目的是为了提供一个自定义的状态对象,以便在构建我们的 MyHomePage StatefulWidget 时使用。
  • State<MyHomePage> createState():这是我们重写的方法。方法的返回类型是 State<MyHomePage>,表示我们将返回一个与 MyHomePage 类型关联的状态对象。这个状态对象将负责管理与 MyHomePage 实例相关的状态。
  • => _MyHomePageState();:这是一个简化的函数体,等同于 { return _MyHomePageState(); }。箭头函数表示我们将创建一个名为 _MyHomePageState 的新状态对象,并将其作为结果返回。

要了解 createState 方法的重要性,我们需要了解 StatefulWidget 的工作原理。StatefulWidget 是一个具有可变状态的 Widget。当 StatefulWidget 的状态发生变化时,框架会重新构建 Widget 树以反映这些更改。为了实现这一点,框架需要知道如何创建与 StatefulWidget 实例关联的状态对象。这就是 createState 方法的作用:告诉框架如何创建状态对象。

在实际应用中,createState 方法通常会返回一个自定义的 State 子类,该子类包含了与 StatefulWidget 实例关联的状态数据和逻辑。这使得 StatefulWidget 可以在其生命周期内保持状态,从而实现动态 UI、响应事件和执行其他与状态相关的操作。

5. 状态类 _MyHomePageState

5.1 看代码

在上一节中,定义了一个名为 MyHomePage 的 有状态组件(继承于StatefulWidget 类)。其 createState 方法中使用了一个名为 _MyHomePageState状态类,该类将在创建 MyHomePage 实例时与其关联。

_MyHomePageState 类是一个自定义的 State 子类,负责管理与 MyHomePage 实例相关的状态。它包含一个 _counter 属性,表示按下按钮的次数,以及一个 _incrementCounter 方法,用于更新 _counter 的值。它还实现了 build 方法,用于构建与 MyHomePage 实例关联的 UI。

_MyHomePageState 类的代码如下:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // 这个对 setState 的调用告诉 Flutter 框架,这个 State 中的某些内容已经发生了变化,
      // 这将导致它重新运行下面的 build 方法,以便显示可以反映更新后的值。如果我们更改了
      // _counter 而没有调用 setState(),那么 build 方法将不会再次被调用,因此什么都不会发生。
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    // 每次调用 setState 时,例如上面的 _incrementCounter 方法所做的,
    // 都会重新运行此方法。

    // Flutter 框架已经过优化,以使得重新运行 build 方法变得更快,
    // 因此你可以重建任何需要更新的内容,而不是必须单独更改 widget 实例。
    return Scaffold(
      appBar: AppBar(
        // 尝试一下:尝试将这里的颜色更改为特定颜色(例如 Colors.amber?),
        // 然后触发热重载以查看 AppBar 的颜色变化,而其他颜色保持不变。

        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        // 这里我们从由 App.build 方法创建的 MyHomePage 对象中获取值,
        // 并将其用于设置我们的 appbar 标题。
        title: Text(widget.title),
      ),
      body: Center(
        // Center 是一个布局 widget。它接受一个子 widget,并将其定位
        // 在父 widget 的中央。
        child: Column(
          // Column 也是一个布局 widget。它接受一组子 widget,并垂直排列它们。
          // 默认情况下,它会自动调整自身尺寸以适应其子 widget 水平方向的尺寸,
          // 并尽量与其父 widget 一样高。

          // Column 具有各种属性来控制它如何调整自身尺寸以及如何定位其子 widget。
          // 在这里,我们使用 mainAxisAlignment 将子 widget 垂直居中;主轴在这里
          // 是垂直轴,因为 Column 是垂直的(交叉轴将是水平的)。

          // 尝试一下:调用 "debug painting"(在 IDE 中选择 "Toggle Debug Paint"
          //操作,或者在控制台中按 "p"),以查看每个 widget 的线框。
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              '你已经按了这个按钮很多次了:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // 这个尾随逗号使得自动格式化在构建方法中更加美观。
    );
  }
}

_MyHomePageState 类应该继承自 State 类,并实现 build 方法以构建与 MyHomePage 实例关联的 UI。

5.2 State 类

State 类的官方文档地址为:https://api.flutter.dev/flutter/widgets/State-class.html

在Flutter中,State类是与StatefulWidget相关的一个重要概念。State对象存储了一个StatefulWidget的可变状态。当状态改变时,State对象会通知Flutter框架重建UI。

State类的生命周期包括以下几个阶段:

阶段描述
createdState对象被创建时,State.initState方法会被调用。
initializedState对象被创建,但还没有准备构建时,State.didChangeDependencies在这个时候会被调用。
readyState对象已经准备好了构建,State.dispose没有被调用的时候。
defunctState.dispose被调用后,State对象不能够被构建。

要改变State对象的状态,可以使用setState方法。setState方法接受一个回调函数,该函数对状态进行修改。当回调函数执行完毕后,Flutter框架将安排重建UI。

下面是一个简单的例子,演示了如何使用State类和setState方法:

class Counter extends StatefulWidget {
  
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;

  void _incrementCounter() {
    setState(() {
      _count = _count + 1;
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('You have pushed the button this many times:'),
        Text('$_count', style: Theme.of(context).textTheme.headline4),
        ElevatedButton(
          onPressed: _incrementCounter,
          child: Text('Increment Counter'),
        ),
      ],
    );
  }
}

在这个例子中,_CounterState类维护了一个名为_count的状态。当用户点击按钮时,_incrementCounter方法会被调用,使用setState方法更新_count的值。这将触发Flutter框架重建UI,以显示更新后的计数值。

5.3 提升按钮:ElevatedButton组件

这是 Flutter 提供的诸多按钮中的一种,其前身为 凸起按钮:RaisedButton组件RaisedButton现在已经被废弃,官方推荐使用 ElevatedButton 替代。

关于 Flutter 的各种按钮类组件及其详细用法的更多介绍,请参考博文《Flutter 组件(三)按钮类组件》:https://blog.csdn.net/qq_28550263/article/details/131387856


F. 附录

F.1 Flutter Demo 完整源代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // 这个 widget 是您应用程序的根。
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // 这是您应用程序的主题。
        //
        // 尝试一下:尝试使用 "flutter run" 运行您的应用程序。您会看到
        // 应用程序具有蓝色的工具栏。然后,在不退出应用的情况下,
        // 尝试将下面 colorScheme 中的 seedColor 更改为 Colors.green,
        // 然后调用 "hot reload"(保存更改或按下 Flutter 支持的 IDE 中的 "hot
        // reload" 按钮,或者如果您使用了命令行启动应用程序,则按 "r")。
        //
        // 注意计数器没有重置为零;应用程序状态在重新加载期间不会丢失。
        // 要重置状态,请使用热重启代替。
        //
        // 这对代码也同样适用,而不仅仅是值:大多数代码更改都可以
        // 通过热重载进行测试。
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter演示主页'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  // 这个 widget 是你的应用程序的主页。它是有状态的,这意味着它有一个 State 对象
  // (在下面定义),其中包含影响其外观的字段。

  // 这个类是 state 的配置。它保存了由父级(在本例中是 App widget)提供的值
  // (在本例中是标题),并被 State 的 build 方法使用。Widget 子类中的字段总是
  // 被标记为 "final"。

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // 这个对 setState 的调用告诉 Flutter 框架,这个 State 中的某些内容已经发生了变化,
      // 这将导致它重新运行下面的 build 方法,以便显示可以反映更新后的值。如果我们更改了
      // _counter 而没有调用 setState(),那么 build 方法将不会再次被调用,因此什么都不会发生。
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    // 每次调用 setState 时,例如上面的 _incrementCounter 方法所做的,
    // 都会重新运行此方法。

    // Flutter 框架已经过优化,以使得重新运行 build 方法变得更快,
    // 因此你可以重建任何需要更新的内容,而不是必须单独更改 widget 实例。
    return Scaffold(
      appBar: AppBar(
        // 尝试一下:尝试将这里的颜色更改为特定颜色(例如 Colors.amber?),
        // 然后触发热重载以查看 AppBar 的颜色变化,而其他颜色保持不变。

        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        // 这里我们从由 App.build 方法创建的 MyHomePage 对象中获取值,
        // 并将其用于设置我们的 appbar 标题。
        title: Text(widget.title),
      ),
      body: Center(
        // Center 是一个布局 widget。它接受一个子 widget,并将其定位
        // 在父 widget 的中央。
        child: Column(
          // Column 也是一个布局 widget。它接受一组子 widget,并垂直排列它们。
          // 默认情况下,它会自动调整自身尺寸以适应其子 widget 水平方向的尺寸,
          // 并尽量与其父 widget 一样高。

          // Column 具有各种属性来控制它如何调整自身尺寸以及如何定位其子 widget。
          // 在这里,我们使用 mainAxisAlignment 将子 widget 垂直居中;主轴在这里
          // 是垂直轴,因为 Column 是垂直的(交叉轴将是水平的)。

          // 尝试一下:调用 "debug painting"(在 IDE 中选择 "Toggle Debug Paint"
          //操作,或者在控制台中按 "p"),以查看每个 widget 的线框。
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              '你已经按了这个按钮很多次了:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // 这个尾随逗号使得自动格式化在构建方法中更加美观。
    );
  }
}

F.2 效果演示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/686514.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RFID技术的革新与应用:连接智能物联网的关键

在日益数字化的时代&#xff0c;物联网&#xff08;IoT&#xff09;技术正迅速发展&#xff0c;并为我们的生活带来了无数的便利。而射频识别&#xff08;RFID&#xff09;技术作为物联网的关键支撑之一&#xff0c;正在推动着智能化、自动化的进程。本文将深入探讨RFID技术的基…

INTERSPEECH 2023论文|基于自监督学习表示的具有持久性口音记忆的口音识别

论文题目&#xff1a; Self-supervised Learning Representation based Accent Recognition with Persistent Accent Memory 作者列表&#xff1a; 李睿&#xff0c;谢志伟&#xff0c;徐海华&#xff0c;彭亦周&#xff0c;刘和鑫&#xff0c;黄浩&#xff0c;Chng Eng Sio…

神州设备IPV6路由综合运用

实训拓扑图 一、基本配置: SW-1: SW-1>ena SW-1#conf SW-1(config)#vlan 10;100 SW-1(config)#int l1 SW-1(config-if-loopback1)#ip add 1.1.1.1 255.255.255.255 SW-1(config-if-loopback1)#ipv6 add 2001:1::1/128 SW-1(config-if-loopback1)#exit

前端系列18集-权限,nginx成功,屏幕分辨率,vue3

vue3.0 使用原生websocket通信 // Websoket连接成功事件const websocketonopen (res: any) > {console.log("WebSocket连接成功", res);};// Websoket接收消息事件const websocketonmessage (res: any) > {console.log("数据", res);};// Websoket…

【从零开始学习C++ | 第二十二篇】C++新增特性(下)

目录 前言&#xff1a; 类型推导&#xff1a; constexpr关键字&#xff1a; 初始化列表&#xff1a; 基于范围的for循环&#xff1a; 智能指针之unique ptr Lambda表达式&#xff1a; 总结&#xff1a; 前言&#xff1a; 本文我们将继续介绍 C 11 新增十大特性的剩余…

解决前端容器不能充满屏幕

解决前端容器不能充满屏幕 px、rpx、em、rem、vw、vh各种像素单位的区别 css3新单位vw、vh、vmin、vmax的使用详解 学习element-UI写管理系统的页面&#xff0c;发现当菜单栏都收缩起来&#xff0c;结果是这样的 红色框是容器里每个板块的布局&#xff0c;但是容器下面却有空白…

如何处理兼容性测试中的变更管理?

如何处理兼容性测试中的变更管理? 在进行软件测试的过程中&#xff0c;兼容性测试是&#xfeff;非常重要的一环。然而&#xff0c;在进行兼容性测试时&#xff0c;由于涉及到不同平台、不同设备的适配问题&#xff0c;可能会出现许多变更管理的情况。这时候&#xff0c;如果没…

阿里企业邮箱收费标准_企业邮箱费用明细表

阿里云企业邮箱收费标准&#xff08;免费版/标准/尊享/集团&#xff09;&#xff0c;2023阿里云企业邮箱收费标准&#xff0c;免费版企业邮箱0元&#xff0c;标准版企业邮箱540元一年&#xff08;原价600元一年&#xff09;&#xff0c;企业邮箱尊享版1400元一年&#xff0c;9折…

4-移动端适配-1

01-移动 Web 基础 谷歌模拟器 模拟移动设备&#xff0c;方便查看页面效果 屏幕分辨率 分类&#xff1a; 物理分辨率&#xff1a;硬件分辨率&#xff08;出厂设置&#xff09;逻辑分辨率&#xff1a;软件 / 驱动设置 结论&#xff1a;制作网页参考 逻辑分辨率 视口 作用&a…

微信小程序项目实例——2048小游戏

今日推荐&#x1f481;‍♂️ 第一次听廖俊涛的歌是他首次出现在明日之子舞台上的那首《谁》 到现在这首歌成了我网易云收藏的十几首歌中的一首&#xff0c;也是听的最多的一首 怎么形容呢&#x1f914;算不上惊艳&#xff0c;却百听不厌&#x1f442; &#x1f52e;&#x1…

直播美颜SDK的商业化应用:开发者需要注意的关键问题

直播美颜SDK是当前直播行业中十分热门的技术之一&#xff0c;它可以为直播平台提供高质量的美颜效果&#xff0c;提升直播用户的使用体验和观看体验。随着直播市场的不断扩大和竞争的加剧&#xff0c;越来越多的直播平台开始使用美颜SDK以提高自身的用户黏性和用户体验。那么&a…

二叉树OJ题:LeetCode--100.相同的树

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下LeetCode中第100道二叉树OJ题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; 数据结构与算法专栏&#xff1a;数据结构与算法 个 人…

脑机接口:运动想象简介

脑机接口&#xff1a;运动想象简介 0. 脑机接口1. 运动想象2. 信号处理2.1 信号采集2.2 信号预处理2.3 特征提取2.4 分类识别 3. EEG波段介绍4. 脑电图电极定位5. 总结 0. 脑机接口 脑机接口&#xff08;Brain-Computer Interface&#xff0c; BCI&#xff09;&#xff1a;它是…

MATLAB 之 可视化图形用户界面设计

这里写目录标题 一、可视化图形用户界面设计1. 图形用户界面设计窗口1.1 图形用户界面设计模板1.2 图形用户界面设计窗口 2. 可视化图形用户界面设计工具1.1 对象属性检查器2.2 菜单编辑器2.3 工具栏编辑器2.4 对齐对象工具2.5 对象浏览器2.6 Tab 键顺序编辑器 3. 可视化图形用…

途乐证券|股票XR是什么意思?买股票为什么赚不到钱?

股票市场上有时会出现一些股票在其名称前加上英文字母的情况&#xff0c;比如XD、XR等。那么股票XR是什么意思&#xff1f;买股票为什么赚不到钱&#xff1f;途乐证券为大家准备了相关内容&#xff0c;以供参考。 股票XR是什么意思&#xff1f; 股票名称中带有XR是表示股票在进…

yolov5-cls部署之onnx导出

本文旨在介绍说明yolov5自带的分类如何导出动态的batch的onnx。其中输出两种形式&#xff1a; 形式&#xff08;1&#xff09;&#xff1a;导出带softmax映射到概率的 形式&#xff08;2&#xff09;&#xff1a;导出不带softmax的&#xff0c;这个也是官方默认的方式 一、动…

连接服务器,再连接VSCode

一、 创建账号&#xff0c;查找公钥 通过命令窗口 a. 打开你的 git bash 窗口 b. 进入 .ssh 目录&#xff1a;cd ~/.ssh c. 找到 id_rsa.pub 文件&#xff1a;ls d. 查看公钥&#xff1a;cat id_rsa.pub 或者 vim id_rsa.pub 查看本机 ssh 公钥&#xff0c;生成公钥 二、用…

Sangfor华东天勇战队:mybatis-plus demo

基本依赖添加&#xff0c;表创建&#xff0c;启动类&#xff0c;测试类 引入依赖&#xff1a; <!-- mybatis-plus 依赖--> <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version…

【vue2】封装文字过长自动省略部分并且鼠标悬浮显示全部

技术&#xff1a;Ant design vue1.7.8 UI框架、vue2.X 需求:实现文字过长自动省略部分&#xff0c;鼠标悬浮显示全部 效果图&#xff1a; 图一&#xff1a; 图二&#xff1a; 1.封装组件代码&#xff1a; src/components/Ellipsis/index.js 文件下代码 import Ellipsis f…

d2l_第七章学习_卷积神经网络

参考: d2l今日学习——卷积神经网络&#xff08;CNN&#xff09;https://blog.csdn.net/m0_61165991/article/details/124176077图像工程&#xff08;上册&#xff09;-图像处理傅里叶变换https://blog.csdn.net/qq_43369406/article/details/131350139 x.1 前储知识&#xff…