当前位置: 首页 > news >正文

第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 CodeFile > Open Folder...,然后选择 my_first_app 文件夹。

    • Android StudioFile > 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: fluttercupertino_icons: ^1.0.2 # 一个提供iOS风格图标的包dev_dependencies: # 开发阶段所依赖的包(如测试框架)flutter_test:sdk: flutterflutter_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});@overrideWidget 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;@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;void _incrementCounter() {setState(() {_counter++;});}@overrideWidget 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),),);}
}
  • StatefulWidget 与 State: 这是一个关键概念。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. 将 MyHomePage 的 title 修改为你自己的名字。

  2. 将 floatingActionButton 的 Icon 从 Icons.add 改为 Icons.favorite

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

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

结语

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

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

http://www.dtcms.com/a/553099.html

相关文章:

  • 使用LangChain+LangGraph自定义AI工作流,实现音视频字幕生成工具
  • 【Matlab】基于模型预测控制(MPC)与滚动时域估计(MHE)集成的目标点镇定研究
  • 基于MATLAB的粒子群算法(PSO)优化libsvm参数完整实现
  • PostgreSQL 的表继承与分区
  • 神经网络之矩阵可逆
  • 笔记:现代操作系统:原理与实现(7)
  • Java-164 MongoDB 认证与权限实战:单实例与分片集群 整体认证配置实战 最小化授权/错误速查/回滚剧本
  • 北京公司的网站建设きょこんきょうしゃ在线
  • 第4讲:理解Flutter的灵魂 - “Everything is a Widget”
  • 驱动精灵、驱动人生、NVIDIA专业显卡驱动、360驱动大师、联想乐驱动,电脑驱动修复工具大全
  • Spring Boot 4与Spring Framework 7:云原生Java的全新革命与企业级实战
  • 虚拟机在云原生与智能时代的未来应用场景探析
  • 电脑如何设置wifi密码,详细步骤教程指南
  • C#面试题及详细答案120道(51-60)-- LINQ与Lambda
  • 北京网站备案的地址ps怎么做网站分隔线
  • DLSS是什么
  • web网页开发,旧版在线%考试,判题%系统demo,基于python+flask+随机分配考试题目,基于开发语言python,数据库mysql
  • 【C++】哈希表封装实现 unordered_map 和 unordered_set
  • 353-Spring AI Alibaba ARK 多模型示例
  • 安徽海绵城市建设协会网站ip查询网站备案查询系统
  • MVVM架构与ICommand核心笔记
  • Web后端开发学习总结
  • 萍乡做网站的公司有哪些门户网站建设方案ppt 百度文库
  • Wireshark抓包教程:获取网站登录凭证
  • 销售驱动的黄昏:医药商业化模式的效率悖论与转型必然
  • 【mysql】锁机制 - 2.行锁间隙锁临键锁
  • 做网站制作需要多少钱网络设计公司有哪些
  • 外卖骑手的Python转型指南:从送餐到编程的实战路径
  • 一款端侧TTS:NeuTTS-Air,3秒语音克隆,声音听起来没有生硬感,语气和节奏感相对自然
  • 网站建设网站软件页面设计属于什么知识产权