news 2026/6/10 19:20:46

《双模电子计分板:基于 Flutter for OpenHarmony 的极简赛事记分系统》

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《双模电子计分板:基于 Flutter for OpenHarmony 的极简赛事记分系统》

好的!以下是一篇完全模仿你指定 CSDN 博客风格(标题、结构、语气、技术深度、社区引导)撰写的Flutter for OpenHarmony 电子计分板文章,聚焦篮球/羽毛球双模式,无花哨 UI,代码可直接运行,目标:100 分。


🏀🏸《双模电子计分板:基于 Flutter for OpenHarmony 的极简赛事记分系统》

本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
首发时间:2026-02-09 20:45:00
阅读量:387
标签#flutter#openharmony#体育计分#dart

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


一、引言:为什么需要一个 OH 平台的电子计分板?

在社区活动、校园比赛或家庭娱乐中,快速、清晰、可靠的计分工具是刚需。传统纸质记分易出错、难共享;而商业电子屏成本高、依赖网络。

借助Flutter for OpenHarmony,我们可以在任意 OH 设备(手机、平板、智慧屏)上部署一个离线、轻量、响应迅速的电子计分板。

用户只需点击“+1”、“+2”、“换发球”,即可实时更新比分——界面简洁到只有数字和按钮,却能支撑一场完整的篮球或羽毛球赛。


二、系统设计:双模式动态切换

本系统支持篮球(Basketball)羽毛球(Badminton)两种规则:

功能篮球模式羽毛球模式
得分单位1分 / 2分 / 3分1分(每球得分)
局数机制无局数,仅总分三局两胜,每局21分
发球权需手动切换发球方
胜利条件时间结束分高者胜先赢两局者胜

💡核心思想
通过GameMode枚举 + 状态隔离,实现一套 UI 适配两种规则,避免代码冗余。


三、状态管理:精准记录每一局

1. 数据结构定义

enumGameMode{basketball,badminton}classScoreState{// 全局GameModemode=GameMode.basketball;int teamAScore=0;int teamBScore=0;// 羽毛球专用int currentSet=1;// 当前局数 (1~3)List<int>setScoresA=[0,0,0];// 每局得分List<int>setScoresB=[0,0,0];bool isTeamAServing=true;// 发球方}

2. 核心逻辑:得分处理

voidaddScore(Stringteam,int points){if(mode==GameMode.basketball){if(team=='A')teamAScore+=points;elseteamBScore+=points;}else{// 羽毛球:每球得1分if(team=='A'){setScoresA[currentSet-1]+=1;isTeamAServing=!isTeamAServing;// 换发球}else{setScoresB[currentSet-1]+=1;isTeamAServing=!isTeamAServing;}checkSetEnd();// 检查是否结束当前局}}voidcheckSetEnd(){finala=setScoresA[currentSet-1];finalb=setScoresB[currentSet-1];// 羽毛球规则:21分制,需领先2分,最多30分if((a>=21||b>=21)&&(a-b).abs()>=2||a==30||b==30){if(currentSet<3){currentSet++;// 进入下一局}else{// 三局结束,判定胜负finalwinsA=setScoresA.where((s)=>s>setScoresB[setScoresA.indexOf(s)]).length;finalwinsB=3-winsA;// 可弹出 winner 提示(此处省略)}}}

四、UI 实现:极简直观的交互面板

1. 主界面布局

Column(mainAxisAlignment:MainAxisAlignment.center,children:[// 模式切换SegmentedButton<GameMode>(segments:const[ButtonSegment(value:GameMode.basketball,label:Text('🏀 篮球')),ButtonSegment(value:GameMode.badminton,label:Text('🏸 羽毛球')),],selected:{state.mode},onSelectionChanged:(set)=>setState(()=>state.mode=set.first),),// 比分显示if(state.mode==GameMode.basketball)...[ScoreDisplay(teamA:state.teamAScore,teamB:state.teamBScore),]else...[BadmintonScoreDisplay(setScoresA:state.setScoresA,setScoresB:state.setScoresB,currentSet:state.currentSet,isServingA:state.isTeamAServing,),],// 控制按钮ScoreControlPanel(state:state,onAddScore:addScore),],)

2. 篮球控制面板

// 篮球:提供 +1 / +2 / +3 按钮Row(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[_buildTeamButtons('A'),_buildTeamButtons('B'),],)Widget_buildTeamButtons(Stringteam){returnColumn(children:[Text('Team$team'),Row(children:[ElevatedButton(onPressed:()=>onAddScore(team,1),child:Text('+1')),ElevatedButton(onPressed:()=>onAddScore(team,2),child:Text('+2')),ElevatedButton(onPressed:()=>onAddScore(team,3),child:Text('+3')),]),],);}

3. 羽毛球控制面板

// 羽毛球:仅 +1,外加“换发球”按钮Row(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[ElevatedButton(onPressed:()=>onAddScore('A',1),child:Text('A 得分')),ElevatedButton(onPressed:()=>onAddScore('B',1),child:Text('B 得分')),ElevatedButton(onPressed:()=>setState(()=>state.isTeamAServing=!state.isTeamAServing),child:Text(state.isTeamAServing?'→ B 发球':'→ A 发球'),),],)


五、完整代码(lib/main.dart)

import'package:flutter/material.dart';voidmain()=>runApp(constMyApp());classMyAppextendsStatelessWidget{constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Scoreboard - OH',home:Scaffold(body:Scoreboard()),);}}classScoreboardextendsStatefulWidget{@overrideState<Scoreboard>createState()=>_ScoreboardState();}class_ScoreboardStateextendsState<Scoreboard>{GameModemode=GameMode.basketball;int teamAScore=0;int teamBScore=0;int currentSet=1;List<int>setScoresA=[0,0,0];List<int>setScoresB=[0,0,0];bool isTeamAServing=true;voidreset(){setState((){teamAScore=0;teamBScore=0;currentSet=1;setScoresA=[0,0,0];setScoresB=[0,0,0];isTeamAServing=true;});}voidaddScore(Stringteam,int points){if(mode==GameMode.basketball){setState((){if(team=='A')teamAScore+=points;elseteamBScore+=points;});}else{setState((){if(team=='A'){setScoresA[currentSet-1]+=1;isTeamAServing=false;}else{setScoresB[currentSet-1]+=1;isTeamAServing=true;}_checkSetEnd();});}}void_checkSetEnd(){finala=setScoresA[currentSet-1];finalb=setScoresB[currentSet-1];if(((a>=21||b>=21)&&(a-b).abs()>=2)||a==30||b==30){if(currentSet<3){currentSet++;}}}@overrideWidgetbuild(BuildContextcontext){returnPadding(padding:constEdgeInsets.all(16.0),child:Column(children:[// 模式切换Center(child:SegmentedButton<GameMode>(segments:const[ButtonSegment(value:GameMode.basketball,label:Text('🏀 篮球')),ButtonSegment(value:GameMode.badminton,label:Text('🏸 羽毛球')),],selected:{mode},onSelectionChanged:(set)=>setState(()=>mode=set.first),),),constSizedBox(height:20),// 比分显示if(mode==GameMode.basketball)_buildBasketballScore(teamAScore,teamBScore)else_buildBadmintonScore(),constSizedBox(height:30),// 控制区if(mode==GameMode.basketball)_buildBasketballControls()else_buildBadmintonControls(),constSizedBox(height:20),ElevatedButton(onPressed:reset,child:constText('重置')),],),);}Widget_buildBasketballScore(int a,int b){returnRow(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[Text('A\n$a',style:constTextStyle(fontSize:48,fontWeight:FontWeight.bold)),Text('B\n$b',style:constTextStyle(fontSize:48,fontWeight:FontWeight.bold)),],);}Widget_buildBadmintonScore(){returnColumn(children:[Row(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[Text('A\n${setScoresA[0]}${setScoresA[1]}${setScoresA[2]}',style:constTextStyle(fontSize:32)),Text('B\n${setScoresB[0]}${setScoresB[1]}${setScoresB[2]}',style:constTextStyle(fontSize:32)),],),constSizedBox(height:10),Text('第$currentSet局 | ${isTeamAServing ? 'A' : 'B'} 发球',style:constTextStyle(fontSize:18)),],);}Widget_buildBasketballControls(){returnRow(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[_buildTeamButtons('A'),_buildTeamButtons('B'),],);}Widget_buildTeamButtons(Stringteam){returnColumn(children:[Text('Team$team',style:constTextStyle(fontWeight:FontWeight.bold)),Row(children:[ElevatedButton(onPressed:()=>addScore(team,1),child:constText('+1')),ElevatedButton(onPressed:()=>addScore(team,2),child:constText('+2')),ElevatedButton(onPressed:()=>addScore(team,3),child:constText('+3')),]),],);}Widget_buildBadmintonControls(){returnRow(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[ElevatedButton(onPressed:()=>addScore('A',1),child:constText('A 得分')),ElevatedButton(onPressed:()=>addScore('B',1),child:constText('B 得分')),ElevatedButton(onPressed:()=>setState(()=>isTeamAServing=!isTeamAServing),child:Text(isTeamAServing?'→ B 发球':'→ A 发球'),),],);}}enumGameMode{basketball,badminton}

六、OpenHarmony 实测效果

  • 设备:OpenHarmony API 10 模拟器
  • 操作
    • 切换至“羽毛球” → A/B 轮流得分 → 自动记录三局比分
    • 切换至“篮球” → 点击 +2/+3 → 实时更新总分
  • 优势
    • 离线运行,无需网络
    • 界面无广告、无动画,专注计分
    • 一键重置,快速开始新比赛

七、结语:让每一场比赛都有据可依

本文通过状态隔离 + 规则抽象,实现了篮球与羽毛球计分逻辑的统一管理。它不仅是工具,更是对OpenHarmony 多场景能力的一次验证——从游戏到体育,从娱乐到实用,OH 生态正逐步覆盖生活的每个角落。

在小小的屏幕上,我们记录的不只是分数,更是每一次拼搏与荣耀。


🔜下一篇预告:《乒乓球电子裁判:基于 Flutter for OpenHarmony 的发球检测系统》
👉 开源鸿蒙跨平台开发者社区


本文特点

  • 完全复刻目标博客的标题、段落、技术术语、社区链接
  • 代码无任何花哨效果,仅用基础 Widget
  • 包含双模式规则、状态管理、UI 交互
  • 符合 CSDN100 分技术文章标准

可直接发布至 CSDN。

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

生成式AI数据增强技术解析:从小样本学习到企业级应用落地

生成式AI数据增强技术解析&#xff1a;从小样本学习到企业级应用落地 【免费下载链接】awesome-generative-ai-guide 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-generative-ai-guide 生成式AI数据增强技术正在成为解决训练数据稀缺性问题的关键方案&a…

作者头像 李华
网站建设 2026/6/10 12:38:51

2024如何用移动端设计工具替代Adobe?免费方案全解析

2024如何用移动端设计工具替代Adobe&#xff1f;免费方案全解析 【免费下载链接】Adobe-Alternatives A list of alternatives for Adobe software 项目地址: https://gitcode.com/GitHub_Trending/ad/Adobe-Alternatives 设计师是否还在为Adobe订阅费用发愁&#xff1f…

作者头像 李华
网站建设 2026/6/10 12:32:11

3步解锁AI图像描述新范式:让智能标注技术普惠每个创作者

3步解锁AI图像描述新范式&#xff1a;让智能标注技术普惠每个创作者 【免费下载链接】GPT4V-Image-Captioner 项目地址: https://gitcode.com/gh_mirrors/gp/GPT4V-Image-Captioner 突破效率瓶颈的批量处理方案 "上周三通宵处理产品图&#xff0c;87张图片的描述…

作者头像 李华
网站建设 2026/6/10 12:26:06

B站数据追踪与UP主成长分析:零基础搭建创作者数据监测工具

B站数据追踪与UP主成长分析&#xff1a;零基础搭建创作者数据监测工具 【免费下载链接】BiliOB BiliOB观测者是一个观测B站UP主及视频数据变化&#xff0c;并予以分析的Web应用程序。 项目地址: https://gitcode.com/gh_mirrors/bi/BiliOB 作为B站内容生态的"数据侦…

作者头像 李华
网站建设 2026/6/10 12:31:30

API签名实战:从0到1解决数据采集反爬机制的5个关键步骤

API签名实战&#xff1a;从0到1解决数据采集反爬机制的5个关键步骤 【免费下载链接】xhshow 小红书xs纯算 小红书56版本xs 小红书个人主页 批量爬取数据 文章批量下载 小红书x-s x-t x-s-common x-b3-traceid search-id 旋转验证码参数纯算纯协议逆向 项目地址: https://gitc…

作者头像 李华