Flutter 入门实战:手把手教你打造一个交互式计数器应用

在 Flutter 开发中,状态管理是最核心的概念之一。为了帮助大家理解如何创建一个能够响应用户操作的界面,本文将通过一个经典的“计数器(Counter)”案例,详细解析代码的结构与逻辑。

最终在虚拟机成功运行事例图片
在这里插入图片描述

1.编码布局图片
在这里插入图片描述

2.完整代码解释

import 'package:flutter/material.dart';

void main() {
  // 应用的入口函数,启动 MyApp 组件
  runApp(const MyApp());
}

// 应用的根组件,通常是无状态的 (StatelessWidget)
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      // 应用标题(浏览器标签页或任务管理器中显示的名称)
      title: '万能的网站',
      // 定义应用主题
      theme: ThemeData(
        // 设置主页背景色为青色 (Teal/Aqua 色系)
        scaffoldBackgroundColor: const Color.fromARGB(255, 62, 192, 201),
      ),
      // 指定首页为 MainPage
      home: const MainPage(),
    );
  }
}

// 主页面组件,因为需要计数(状态变化),所以使用有状态组件 (StatefulWidget)
class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);

  
  _MainPageState createState() => _MainPageState();
}

// 主页面的状态类,负责管理数据和界面刷新
class _MainPageState extends State<MainPage> {
  // 定义计数器变量,默认值为 12
  // 在 Dart 中,以下划线 _ 开头的变量表示私有 (private)
  int _count = 0;

  
  Widget build(BuildContext context) {
    return Scaffold(
      // 顶部应用栏
      appBar: AppBar(
        title: const Text("欢迎来到小晚的课堂"),
      ),
      // 主体内容区域
      body: Center(
        // 使用 Row (行) 组件让内容水平排列
        child: Row(
          // 主轴方向居中对齐
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 减号按钮
            TextButton(
              onPressed: () {
                // 修改状态必须包裹在 setState 中,否则界面不会刷新
                setState(() {
                  _count--; // 点击减 1
                });
              },
              child: const Text("-"),
            ),
            // 显示数字的文本
            Text("$_count"),
            // 加号按钮
            TextButton(
              onPressed: () {
                // 同样需要使用 setState 通知框架状态已改变
                setState(() {
                  _count++; // 点击加 1
                });
              },
              child: const Text("+"),
            ),
          ],
        ),
      ),
    );
  }
}
3. 项目入口与主框架 (main.dart)

任何 Flutter 应用都从 main 函数开始执行。

import 'package:flutter/material.dart';

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

在这里插入图片描述

  • import 'package:flutter/material.dart';: 引入 Material UI 库,这是 Flutter 提供的一套遵循 Google Material Design 规范的组件库,包含了按钮、文本、布局等基本控件。
  • runApp(const MyApp());: 这是 Flutter 的入口函数。它将 MyApp 组件放入全屏容器中,并启动应用。
4. 根组件 MyApp (无状态组件)

MyApp 通常是应用的根组件,负责定义应用的整体外观,如主题和标题。

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "万能的网站",
      theme: ThemeData(
        scaffoldBackgroundColor: const Color.fromARGB(255, 62, 192, 201),
      ),
      home: const MainPage(),
    );
  }
}

在这里插入图片描述

  • StatelessWidget: 这是一个无状态组件。顾名思义,它的属性是不可变的(final),一旦构建出来,其外观就不会随用户操作而改变。它主要用于展示静态内容。
  • MaterialApp: 这是一个“脚手架”组件,提供了应用的基本结构,包括导航栏(AppBar)、主题颜色和页面栈。
  • home: const MainPage(): 指定了应用启动时显示的首页为 MainPage 组件。这里使用了 const 构造函数,有助于性能优化。
5. 核心业务 MainPage (有状态组件)

计数器的核心逻辑都在这里。因为数字会随点击而变化(状态改变),所以我们必须使用 StatefulWidget

class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);

  
  _MainPageState createState() => _MainPageState();
}

在这里插入图片描述

  • StatefulWidget: 有状态组件。它本身是不可变的,但它持有一个 State 对象(即下面的 _MainPageState),由该对象来管理可变的数据(如计数器数值)。
  • createState(): 这是一个必须重写的方法,它负责创建与该组件配对的状态类实例。
6. 状态管理与 UI 构建 (_MainPageState)

这是整个应用最核心的部分,包含了数据定义和界面构建。

A. 数据定义 (状态变量)

class _MainPageState extends State<MainPage> {
  int _count = 0; // 定义计数器变量,默认值为 0
  // ...
}

在这里插入图片描述

  • int _count = 0;: 这里定义了一个名为 _count 的整型变量。注意变量名前的下划线 _,这在 Dart 中表示该变量是私有的,只能在当前文件或类内部访问,这是良好的编程习惯。

B. 构建界面 (build 方法)


Widget build(BuildContext context) {
  return Center(
    child: Row(
      mainAxisAlignment: MainAxisAlignment.min,
      children: [
        // 减号按钮
        TextButton(
          onPressed: () {
            setState(() {
              _count--;
            });
          },
          child: const Text("减"),
        ),
        // 显示数字的文本
        Text("$_count"),
        // 加号按钮
        TextButton(
          onPressed: () {
            setState(() {
              _count++;
            });
          },
          child: const Text("加"),
        ),
      ],
    ),
  );
}

在这里插入图片描述

  • Center: 一个布局组件,顾名思义,它将其子组件放在屏幕的正中间
  • Row: 一个水平布局组件,它将子组件按照水平方向依次排列(从左到右)。
  • mainAxisAlignment: MainAxisAlignment.min: 这是 Row 的一个属性,表示子组件在主轴(水平方向)上尽可能少地占用空间,使它们紧凑地聚集在中间,而不是拉伸到屏幕两端。
  • Text("$_count"): 显示当前计数器的值。Dart 的字符串插值语法 "$变量名" 会自动将 _count 的数值转换为字符串显示出来。
7. 交互逻辑:如何让数字动起来?

这是初学者最容易困惑的地方。为什么点击按钮数字会变?关键在于 setState

以加号按钮为例:

TextButton(
  onPressed: () {
    setState(() {
      _count++;
    });
  },
  child: const Text("加"),
);

在这里插入图片描述

  1. onPressed: 这是 TextButton 的点击回调属性。当用户点击按钮时,这里面的代码就会执行。
  2. setState(() { ... }): 这是 StatefulWidget 提供的一个特殊方法。
    • 它告诉 Flutter:“我要修改界面数据了,请重新运行 build 方法来更新界面。”
    • 如果不调用 setState,虽然 _count 的数值在后台变了,但 build 方法不会重新执行,界面上的数字也就不会刷新
  3. _count++: 在 setState 的回调函数中,执行变量自增操作。

减号按钮 (_count--) 的逻辑与此完全相同,只是操作相反。

总结
  1. 声明式 UI:使用嵌套的 Widget 描述界面长什么样。
  2. 状态驱动:当数据(State)改变时,通过 setState 触发 UI 重新渲染。

这个简单的计数器应用涵盖了 Flutter 开发中最基础也是最重要的布局、组件和状态管理概念。希望这篇解析能帮助你更好地理解代码的运行机制!

🌐 加入社区

欢迎加入 开源鸿蒙跨平台开发者社区,获取最新资源与技术支持:
👉 开源鸿蒙跨平台开发者社区

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐