news 2026/9/14 6:59:25

用 Flutter 做一个“会呼吸”的情绪灯 —— 不写 App,只玩光与动效

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Flutter 做一个“会呼吸”的情绪灯 —— 不写 App,只玩光与动效

用 Flutter 做一个“会呼吸”的情绪灯 —— 不写 App,只玩光与动效**

当人们谈起 Flutter,总说:“跨平台”、“高性能 UI”、“Material Design”。
但今天,我们不做一个 App,不写列表、不连 API、不搞登录页。

我们要用 Flutter 做一盏会呼吸的 RGB 情绪灯—— 一个运行在手机或桌面端的圆形渐变灯光,能随心跳般缓慢明暗变化,还能点击切换颜色模式。它像夜里的小夜灯,温柔地照亮你的代码世界。

这不是又一个 Todo List 教程,而是一次对Flutter 动画与视觉表达能力的诗意探索


🌌 项目目标

  • 创建一个全屏柔和发光的圆形“灯”
  • 使用CustomPainter手绘光晕
  • 通过AnimationController实现“呼吸”效果(缩放 + 透明度联动)
  • 点击切换颜色主题:暖白 → 珊瑚红 → 靛蓝 → 薄荷绿
  • 支持背景透明,营造悬浮光感

它没用,但它美。而这,正是技术浪漫主义的意义。


✅ 准备工作

flutter create mood_lampcdmood_lamp

无需第三方依赖,纯原生 Flutter + Dart 实现。


🎨 第一步:设置透明全屏窗口(仅桌面/移动端适用)

为了让灯光“浮”在屏幕上,我们启用透明背景和无 AppBar 的全屏显示。

main.dart
import'package:flutter/material.dart';import'package:window_manager/window_manager.dart';// 可选:用于桌面端去边框voidmain()async{WidgetsFlutterBinding.ensureInitialized();// 【可选】桌面端配置透明无边框if(isDesktop()){awaitwindowManager.ensureInitialized();WindowOptionswindowOptions=constWindowOptions(size:Size(400,400),center:true,transparent:true,frameless:true,);windowManager.waitUntilReadyToShow(windowOptions,()async{awaitwindowManager.show();});}runApp(constMoodLampApp());}boolisDesktop()=>['windows','macos','linux'].contains(Theme.of(null).platform?.toString());classMoodLampAppextendsStatelessWidget{constMoodLampApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(debugShowCheckedModeBanner:false,home:Scaffold(backgroundColor:Colors.transparent,// 关键:让背景透下去body:constLampBody(),),);}}

💡 提示:安卓/iOS 上也能实现类似效果,只需将Scaffold背景设为透明并使用沉浸式状态栏。


🖌️ 第二步:自定义绘制“光晕”——使用CustomPainter

我们将创建一个动态模糊光圈,靠多重圆环叠加模拟真实灯光扩散。

painters/lamp_painter.dart
// painters/lamp_painter.dartimport'dart:math';import'package:flutter/material.dart';classLampPainterextendsCustomPainter{finalColorcolor;finaldouble intensity;// 呼吸强度 [0.0 - 1.0]LampPainter(this.color,this.intensity);@overridevoidpaint(Canvascanvas,Sizesize){finalcenter=Offset(size.width/2,size.height/2);finalradius=min(size.width,size.height)*0.3;finalpaint=Paint()..blendMode=BlendMode.srcOver;// 绘制多层扩散光圈(从内到外)for(int i=0;i<8;i++){finalalpha=(1.0-i/10)*intensity;finalspread=1.0+i*0.3;paint.shader=RadialGradient(colors:[color.withOpacity(alpha*0.8),Colors.transparent,],).createShader(Rect.fromCircle(center:center,radius:radius*spread),);canvas.drawCircle(center,radius*spread,paint);}}@overrideboolshouldRepaint(covariantLampPainteroldDelegate){returnoldDelegate.color!=color||oldDelegate.intensity!=intensity;}}

💓 第三步:呼吸动画控制器

我们希望灯光像呼吸一样起伏,周期约 4 秒一次。

widgets/breathing_lamp.dart
// widgets/breathing_lamp.dartimport'package:flutter/material.dart';import'../painters/lamp_painter.dart';classBreathingLampextendsStatefulWidget{constBreathingLamp({super.key});@overrideState<BreathingLamp>createState()=>_BreathingLampState();}class_BreathingLampStateextendsState<BreathingLamp>withSingleTickerProviderStateMixin{lateAnimationController_controller;List<Color>_colors=[Colors.white70,Colors.deepOrange.shade300,Colors.indigo.shade200,Colors.tealAccent.withOpacity(0.6),];int _colorIndex=0;ColorgetcurrentColor=>_colors[_colorIndex];@overridevoidinitState(){super.initState();_controller=AnimationController(vsync:this,duration:constDuration(seconds:4),)..repeat(reverse:true);// 自动往返重复}@overridevoiddispose(){_controller.dispose();super.dispose();}voidchangeColor(){setState((){_colorIndex=(_colorIndex+1)%_colors.length;});}@overrideWidgetbuild(BuildContextcontext){returnGestureDetector(onTap:changeColor,child:AnimatedBuilder(animation:_controller,builder:(context,child){// 将动画值映射为呼吸强度:sin 波形更自然finalintensity=sin(_controller.value*pi)*0.6+0.7;returnCustomPaint(painter:LampPainter(currentColor,intensity),child:Container(width:double.infinity,height:double.infinity,alignment:Alignment.center,child:Opacity(opacity:intensity*0.4,child:Text('tap\nto\nchange',textAlign:TextAlign.center,style:TextStyle(fontSize:12,color:currentColor,fontWeight:FontWeight.bold,shadows:[BoxShadow(blurRadius:4,color:Colors.black.withOpacity(0.3),)],),),),),);},),);}}

🔗 最后一步:连接所有部分

更新main.dart中的LampBody
classLampBodyextendsStatelessWidget{constLampBody({super.key});@overrideWidgetbuild(BuildContextcontext){returnContainer(decoration:constBoxDecoration(gradient:LinearGradient(begin:Alignment.topCenter,end:Alignment.bottomCenter,colors:[Color(0xFF111122),Color(0xFF0A0A0F)],// 深色背景衬托光),),child:constBreathingLamp(),);}}

🎥 运行效果

flutter run-dmacos# 或 windows, android, ios

你会看到:

  • 屏幕中央有一团柔和的发光体
  • 光芒缓慢明暗变化,如同呼吸
  • 点击任意位置,灯光切换色调
  • 文字提示轻微闪烁,几乎融入光影

就像房间里的一盏小灯,安静陪伴你深夜 coding。


🧩 技术亮点解析

特性作用
RadialGradient + Shader实现真实光晕扩散
BlendMode.srcOver让多层光叠加更自然
sin(_controller.value * π)模拟生理级呼吸节奏(非线性)
GestureDetector全区域响应点击换色
CustomPainter.shouldRepaint性能优化,避免不必要的重绘

🌈 可扩展方向(让你的灯更聪明)

  • 添加陀螺仪感应:设备倾斜时光晕偏移
  • 接入音乐频谱:灯光随节奏脉动(使用just_audio分析音频)
  • 定时熄灭:30 分钟后自动渐暗(助眠模式)
  • 多灯协作:局域网内多个设备同步呼吸(WebSocket)
  • 打包成屏保或桌面装饰工具

结语:Flutter 是光的画布

我们习惯把 Flutter 当作“做 App 的工具”,
但它本质上是一个像素级可控的视觉引擎

它可以是列表、表单、购物车,
也可以是一束光、一阵风、一声低语。

下次当你打开编辑器,不妨问自己:

“我能用代码,创造出一点美的东西吗?”

这盏小小的“情绪灯”不会帮你赚钱,也不会上架商店,
但它会在某个加班的夜里,轻轻告诉你:

“嘿,你还好吗?”


📦 完整项目结构建议

mood_lamp/ ├── lib/ │ ├── main.dart │ ├── painters/lamp_painter.dart │ └── widgets/breathing_lamp.dart ├── assets/ # 可留空 ├── pubspec.yaml # 无需额外依赖(除 window_manager 可选) └── README.md

GitHub 标题建议写:「A breathing mood lamp built with Flutter — because code can be poetic.」


“Light is not just physics. It’s feeling.”
— 用 Flutter 写动画的人,都是追光者。
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

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

蓝桥杯JAVA--启蒙之路(三)语句

一前言今天依旧更新有关JAVA基础的知识&#xff0c;唉。自从更新JAVA之后浏览量什么的都下降了&#xff0c;可能是大家也不喜欢这么枯燥的基础学习吧&#xff0c;但是基础还是很重要的&#xff0c;明天和后天可能会停更&#xff0c;因为我要回家了。二主要内容if条件判断&#…

作者头像 李华
网站建设 2026/9/13 23:06:51

金融级情绪识别模型训练全攻略(基于千万级对话数据的优化经验)

第一章&#xff1a;金融客服Agent情绪识别的技术背景与业务价值 在金融服务领域&#xff0c;客户与客服代理&#xff08;Agent&#xff09;之间的交互质量直接影响用户满意度与品牌信任度。随着人工智能技术的发展&#xff0c;尤其是自然语言处理与语音情感分析的进步&#xff…

作者头像 李华
网站建设 2026/9/13 2:28:50

计算机系统基础 bufbomb 实验三

听报告无事&#xff0c;顺手写下做过的实验报告,话不多说&#xff0c;开始正文1、实验目的加深对IA-32函数调用规则和栈帧结构的理解。2、实验原理对目标程序实施缓冲区溢出攻击&#xff0c;通过造成缓冲区溢出来破坏目标程序的栈帧结构&#xff0c;继而执行一些原来程序中没有…

作者头像 李华
网站建设 2026/9/14 16:39:27

Tomcat内存机制以及按场景调优

Tomcat内存机制深度解析与场景化调优 Tomcat作为Java生态中最主流的Web容器&#xff0c;其内存管理直接决定应用的稳定性、响应速度和并发能力。本文将从内存机制底层原理、内存区域划分、常见问题根源&#xff0c;到不同业务场景的调优策略&#xff0c;进行超详细、全维度的拆…

作者头像 李华
网站建设 2026/9/14 1:28:18

ConvertX:自托管的在线文件转换器

ConvertX&#xff1a;自托管的在线文件转换器 在当今信息化时代&#xff0c;文件格式的多样性带来了很多不便。无论是处理文档、图像、视频还是音频&#xff0c;往往需要将文件转换成适合自己需求的格式。为了解决这一问题&#xff0c;ConvertX应运而生&#xff0c;它是一款强大…

作者头像 李华
网站建设 2026/9/14 14:24:10

2025年支持企业实现社会价值与商业价值的战略

在2025年&#xff0c;企业面临的挑战是同时实现社会价值与商业价值。通过创新战略&#xff0c;企业可以有效应对这一挑战。首先&#xff0c;构建以社会责任为核心的商业模式&#xff0c;将信任与责任感融入品牌之中&#xff0c;能够带来更高的顾客忠诚度和市场竞争力。其次&…

作者头像 李华