第3讲:创建并运行你的第一个Flutter应用

从项目结构到热重载,全方位解密你的第一个Flutter工程。

你好,欢迎回到《Flutter入门到精通》专栏。在上一讲中,我们成功搭建了开发环境并运行了默认应用。现在,是时候打开这个项目的"黑箱",看看里面究竟有什么,并理解这一切是如何运作的了。

本讲将带你深入Flutter项目的内部,从目录结构到核心代码,让你对Flutter项目有一个全面的认识。

一、创建项目与剖析目录结构

1.1 创建项目

让我们首先通过命令行创建一个新项目,重温上一讲的内容:

  1. 打开终端(或命令提示符/PowerShell)。

  2. 导航到你希望存放项目的目录(例如 cd ~/Documents/FlutterProjects)。

  3. 运行创建命令:

    bash

    复制代码
    flutter create my_first_app
  4. 使用你喜欢的IDE(VS Code或Android Studio)打开这个项目。

    • VS Code : File > Open Folder...,然后选择 my_first_app 文件夹。

    • Android Studio : File > Open...,然后选择 my_first_app 文件夹。

现在,让我们来看看Flutter为我们生成了什么。

1.2 项目根目录解析

你的项目根目录看起来应该是这样的:

text

复制代码
my_first_app/
├── android/          # Android平台的特定代码和配置
├── build/            # 构建生成的文件(自动生成,勿手动修改)
├── ios/              # iOS平台的特定代码和配置
├── lib/              # **这是我们主要的战场!Flutter Dart代码所在地**
├── linux/            # Linux桌面端特定代码
├── macos/            # macOS桌面端特定代码
├── test/             # 单元测试和Widget测试代码
├── web/              # Web端特定代码
├── windows/          # Windows桌面端特定代码
├── .gitignore        # Git版本控制忽略文件配置
├── .metadata         # IDE的元数据(自动生成)
├── .packages         # 项目依赖包路径(自动生成)
├── analysis_options.yaml # 静态代码分析配置
├── my_first_app.iml  # IDE模块文件(自动生成)
├── pubspec.lock      # 锁定依赖版本(自动生成)
├── pubspec.yaml      # **项目的核心配置文件(依赖、资源等)**
└── README.md         # 项目说明文档

核心目录说明:

  • android/ios/ : 包含了各自平台的"外壳"代码。当你需要添加原生插件或进行特定平台配置时,才会深入这些目录。对于初学者,99%的时间你不需要改动它们。

  • lib/ : 这是你未来绝大部分开发工作发生的地方。 所有的Dart代码文件都放在这里。默认情况下,它包含一个 main.dart 文件,这是应用的入口点。

  • pubspec.yaml : 项目的"心脏"。它管理着项目的元数据(如名称、描述、版本)、依赖的三方包、以及图片、字体等资源文件的声明。我们稍后会详细讲解。

  • test/: 用于编写自动化测试代码,保证应用质量。

Flutter的理念 : Flutter试图将不同平台的差异屏蔽掉,让你能在 lib/ 目录中用统一的Dart代码处理大部分逻辑和UI,从而实现真正的跨平台。


二、详解 pubspec.yaml:项目的依赖管家

这个文件至关重要,我们必须要理解它。打开 pubspec.yaml,它看起来像这样:

yaml

复制代码
name: my_first_app # 项目名称
description: "A new Flutter project." # 项目描述

publish_to: 'none' # 不发布到pub.dev(内部项目通常如此)

version: 1.0.0+1 # 应用版本号 (版本名+构建号)

environment:
  sdk: '>=3.0.0 <4.0.0' # 依赖的Dart SDK版本范围

dependencies: # 项目运行时所依赖的包
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2 # 一个提供iOS风格图标的包

dev_dependencies: # 开发阶段所依赖的包(如测试框架)
  flutter_test:
    sdk: flutter
  flutter_lints: ^2.0.0 # 代码规范检查工具

flutter: # Flutter特定的配置
  uses-material-design: true # 是否使用Material Design图标

  # 在这里添加你的资源文件,比如图片、字体
  assets:
    - images/a_dot_burr.jpeg
    - images/a_dot_ham.jpeg

关键部分:

  • dependencies : 当你需要添加新的功能包(如网络请求http、状态管理provider)时,就在这里声明。

  • dev_dependencies: 用于添加开发工具,如测试框架、代码检查工具。

  • flutter -> assets : 当你需要在应用中使用图片时,必须在这里声明! 否则会报错。

修改 pubspec.yaml 后,你必须在你IDE的终端中执行 flutter pub get 命令(或点击IDE提示的"Pub get"按钮)来下载和更新依赖。


三、初识 lib/main.dart:应用的起点

现在,让我们打开 lib/main.dart 文件,这里是整个Flutter应用的入口。初始代码可能看起来有点复杂,但别担心,我们来逐块解析。

3.1 应用入口:main 函数

每个Dart程序的执行都从 main 函数开始。Flutter应用也不例外。

dart

复制代码
void main() {
  runApp(const MyApp());
}
  • void main(): 这是所有Dart应用的入口函数。

  • runApp(): 这是Flutter框架提供的函数,它接收一个Widget 作为参数,并使其成为应用的根Widget 。在这里,根Widget是一个 MyApp 类的实例。

3.2 根Widget:MyApp

MyApp 是一个无状态的Widget(StatelessWidget),它通常用于设置应用的全局主题、路由等。

dart

复制代码
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
  • class MyApp extends StatelessWidget: 这定义了一个名为 MyApp 的类,它继承自 StatelessWidget(一个自身状态不会改变的Widget)。

  • build 方法: 每个Widget都必须实现 build 方法,它描述了如何根据其他较低级别的Widget来构建这个Widget。它返回一个 Widget

  • MaterialApp: 这是一个非常重要的Widget,它封装了应用实现Material Design所需的大部分功能,比如主题、路由、标题等。

    • home: 它定义了应用启动后显示的第一个页面,也就是 MyHomePage

3.3 主页:MyHomePage

MyHomePage 是一个有状态的Widget(StatefulWidget),因为它有一个可以变化的计数器数据 _counter

dart

复制代码
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

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

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
  • StatefulWidgetState : 这是一个关键概念。MyHomePage 类本身是不可变的,但它关联了一个 _MyHomePageState 类。状态(即可变数据 _counter)和改变状态的方法(_incrementCounter)都存在于 State 对象中。

  • setState 方法 : 当你修改了状态数据(如 _counter++),你必须setState 的回调函数中调用它。这会通知Flutter框架:"状态改变了,请重新绘制UI!"。Flutter会随后调用 build 方法,用新的数据重建Widget树,从而更新界面。

  • Scaffold : 这是一个Material Design的布局结构,它提供了默认的应用栏(appBar)、主体内容区域(body)和浮动操作按钮(floatingActionButton)等"脚手架"。


四、体验"热重载"的神奇魅力

现在,让我们来体验Flutter开发中最令人兴奋的功能之一。

  1. 确保你的应用正在运行(通过 flutter run 或在IDE中点击运行按钮)。

  2. 打开 lib/main.dart 文件。

  3. 找到显示数字的 Text 部分:

    dart

    复制代码
    Text(
      '$_counter',
      style: Theme.of(context).textTheme.headlineMedium,
    ),
  4. 我们把它修改得更个性化一点:

    dart

    复制代码
    Text(
      '$_counter',
      style: Theme.of(context).textTheme.headlineMedium?.copyWith(color: Colors.red), // 文字变红色
    ),
  5. 保存文件 (Ctrl+S / Cmd+S)。

见证奇迹的时刻!你设备上的应用界面几乎在瞬间就更新了,数字变成了红色,而且计数器的值保持不变!

热重载的工作原理:

Flutter的Dart虚拟机(JIT模式)将你更新后的代码注入到正在运行的Dart虚拟机中。然后Flutter框架会重建整个Widget树,从而让你立刻看到更改的效果,同时保留应用的状态(比如当前的 _counter 值)。

这与完全重新启动应用相比,节省了大量的开发时间,让你可以快速地进行UI实验和调试。


动手实践

为了加深理解,请尝试以下操作:

  1. MyHomePagetitle 修改为你自己的名字。

  2. floatingActionButtonIconIcons.add 改为 Icons.favorite

  3. body 中的提示文字 'You have pushed the button this many times:' 改为中文,例如 '你已经点击了这么多次按钮:'

在每次修改后,都使用热重载来查看变化。

结语

恭喜!在这一讲中,你不仅了解了Flutter项目的骨架,还亲手修改了代码,并体验了革命性的热重载功能。你已经从一个环境的搭建者,变成了一个真正的Flutter代码探索者。

在下一讲中,我们将深入讲解Flutter最核心的概念------Widget ,并详细解析 StatelessWidgetStatefulWidget 的区别与用法。这是你成为Flutter开发者的关键一步,我们不见不散!

相关推荐
GBVFtou6 小时前
flutter写后感 构建您的第一个 Flutter 应用
flutter
2501_938963969 小时前
Flutter 3.19 桌面应用开发:适配 Windows/macOS 端窗口大小与菜单栏自定义
windows·flutter·macos
星释9 小时前
鸿蒙Flutter三方库适配指南:07.插件开发
flutter·华为·harmonyos
SoaringHeart1 天前
Flutter疑难解决:单独让某个页面的电池栏标签颜色改变
前端·flutter
西西学代码1 天前
Flutter---个人信息(3)---实现修改性别
flutter
西西学代码1 天前
Flutter---ListTile列表项组件
flutter
西西学代码1 天前
Flutter---个人信息(1)---实现简单的UI
开发语言·javascript·flutter
程序员老刘1 天前
Dart宏被砍掉的真相:为什么Go、Python、Java等高级语言都拒绝宏?
flutter·编程语言·dart
月伤591 天前
Flutter中的Text换行问题
flutter