news 2026/3/28 8:16:28

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter for OpenHarmony入门实战:手把手教你打造一个交互式计数器应用

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

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

最终在虚拟机成功运行事例图片

1.编码布局图片

2.完整代码解释

import'package:flutter/material.dart';voidmain(){// 应用的入口函数,启动 MyApp 组件runApp(constMyApp());}// 应用的根组件,通常是无状态的 (StatelessWidget)classMyAppextendsStatelessWidget{constMyApp({Key?key}):super(key:key);@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(// 应用标题(浏览器标签页或任务管理器中显示的名称)title:'万能的网站',// 定义应用主题theme:ThemeData(// 设置主页背景色为青色 (Teal/Aqua 色系)scaffoldBackgroundColor:constColor.fromARGB(255,62,192,201),),// 指定首页为 MainPagehome:constMainPage(),);}}// 主页面组件,因为需要计数(状态变化),所以使用有状态组件 (StatefulWidget)classMainPageextendsStatefulWidget{constMainPage({Key?key}):super(key:key);@override_MainPageStatecreateState()=>_MainPageState();}// 主页面的状态类,负责管理数据和界面刷新class_MainPageStateextendsState<MainPage>{// 定义计数器变量,默认值为 12// 在 Dart 中,以下划线 _ 开头的变量表示私有 (private)int _count=0;@overrideWidgetbuild(BuildContextcontext){returnScaffold(// 顶部应用栏appBar:AppBar(title:constText("欢迎来到小晚的课堂"),),// 主体内容区域body:Center(// 使用 Row (行) 组件让内容水平排列child:Row(// 主轴方向居中对齐mainAxisAlignment:MainAxisAlignment.center,children:[// 减号按钮TextButton(onPressed:(){// 修改状态必须包裹在 setState 中,否则界面不会刷新setState((){_count--;// 点击减 1});},child:constText("-"),),// 显示数字的文本Text("$_count"),// 加号按钮TextButton(onPressed:(){// 同样需要使用 setState 通知框架状态已改变setState((){_count++;// 点击加 1});},child:constText("+"),),],),),);}}
3. 项目入口与主框架 (main.dart)

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

import'package:flutter/material.dart';voidmain(){runApp(constMyApp());}

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

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

classMyAppextendsStatelessWidget{constMyApp({Key?key}):super(key:key);@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:"万能的网站",theme:ThemeData(scaffoldBackgroundColor:constColor.fromARGB(255,62,192,201),),home:constMainPage(),);}}

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

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

classMainPageextendsStatefulWidget{constMainPage({Key?key}):super(key:key);@override_MainPageStatecreateState()=>_MainPageState();}

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

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

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

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

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

B. 构建界面 (build方法)

@overrideWidgetbuild(BuildContextcontext){returnCenter(child:Row(mainAxisAlignment:MainAxisAlignment.min,children:[// 减号按钮TextButton(onPressed:(){setState((){_count--;});},child:constText("减"),),// 显示数字的文本Text("$_count"),// 加号按钮TextButton(onPressed:(){setState((){_count++;});},child:constText("加"),),],),);}

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

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

以加号按钮为例:

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

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

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

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

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

🌐 加入社区

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/20 20:02:46

Qwen3-Embedding-4B内存溢出?参数详解与调优实战

Qwen3-Embedding-4B内存溢出&#xff1f;参数详解与调优实战 在部署大模型服务时&#xff0c;内存溢出&#xff08;OOM&#xff09;是开发者最常遇到的“拦路虎”之一。尤其是像 Qwen3-Embedding-4B 这类参数量达到 40 亿级别的嵌入模型&#xff0c;在高并发或长文本场景下极易…

作者头像 李华
网站建设 2026/3/22 1:53:38

MinerU如何提升推理速度?CUDA驱动优化实战

MinerU如何提升推理速度&#xff1f;CUDA驱动优化实战 1. 引言&#xff1a;为什么PDF提取需要GPU加速&#xff1f; 处理复杂排版的PDF文档一直是自然语言处理和文档智能领域的难点。尤其是当文档中包含多栏布局、数学公式、表格和图片时&#xff0c;传统方法往往难以准确还原…

作者头像 李华
网站建设 2026/3/17 1:52:43

如何高效做语音识别?试试科哥开发的SenseVoice Small镜像工具

如何高效做语音识别&#xff1f;试试科哥开发的SenseVoice Small镜像工具 1. 为什么传统语音识别用起来这么麻烦&#xff1f; 你有没有遇到过这种情况&#xff1a;录了一段会议音频&#xff0c;想转成文字整理纪要&#xff0c;结果打开软件发现要联网、要收费、还要等十几分钟…

作者头像 李华
网站建设 2026/3/27 15:21:58

Z-Image-Turbo性能优化技巧,让生成速度再提升

Z-Image-Turbo性能优化技巧&#xff0c;让生成速度再提升 你是否也在使用Z-Image-Turbo时感觉“明明配置不低&#xff0c;但生成还是不够快”&#xff1f;或者在批量出图时被漫长的等待折磨得失去耐心&#xff1f;别急——这并不是模型的问题&#xff0c;而是你还没掌握它的“…

作者头像 李华
网站建设 2026/3/14 14:51:17

测试开机启动脚本权限设置详解,chmod一步到位

测试开机启动脚本权限设置详解&#xff0c;chmod一步到位 1. 开机自启脚本的核心问题&#xff1a;权限与执行环境 你有没有遇到过这样的情况&#xff1a;写好了一个启动脚本&#xff0c;配置了开机自动运行&#xff0c;结果重启后发现什么都没发生&#xff1f; 不是脚本没执行…

作者头像 李华
网站建设 2026/3/27 17:53:05

万物皆可分!SAM3文本引导分割技术深度解读

万物皆可分&#xff01;SAM3文本引导分割技术深度解读 1. 引言&#xff1a;从“抠图”到“万物分割”的跨越 你有没有遇到过这样的情况&#xff1f;想把一张照片里的某个物体单独提取出来&#xff0c;比如一只狗、一辆红色汽车&#xff0c;或者一件蓝色衬衫&#xff0c;但手动…

作者头像 李华