news 2026/4/27 0:48:41

用 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/4/25 18:21:40

某海外 _signature签名分析

1. 目标 aHR0cHM6Ly93d3cudGlrdG9rLmNvbS9hcGkvc2hvcC91cy9ob21lcGFnZV9kZXNrdG9wL3NlYXJjaF93b3JkX3N1Z2dlc3Rpb24/bXNUb2tlbj1mWEItOHRoRU9hNllIblkyellKM1lLaDlBMUtGeks3NnpXWjk2bnRwMUlldjNjTDFBdmNQRllpTmtLVllXUThLNVhYUkdJRFd4VjM2ekxWWEtPNFNLLWNGUFpjLU44cGhab1pWMW1k…

作者头像 李华
网站建设 2026/4/25 10:06:16

【毕业设计】基于springboot+微信小程序的集换社卡牌的交易系统小程序(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/25 4:21:33

计算机小程序毕设实战-基于SpringBoot的交通违法有奖曝光平台设计与基于springboot+微信小程序的的交通违法有奖曝光平台【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/25 9:36:13

HTML行内块标签——img、表单、音视频标签

目录 概念&#xff1a;特殊的标签&#xff0c;有自己独有的功能 img标签&#xff1a; 表单&#xff1a; 1、input表单项 2、下拉框表单项:select 3、内容框&#xff1a;textarea 4、按钮 button 5、去除表单默认样式 ​编辑 音视频标签 概念&#xff1a;特殊的标签&a…

作者头像 李华
网站建设 2026/4/17 0:25:16

微信ipad协议,wechatapi,个人号二次开发

微信生态安全挑战与防护策略微信作为拥有13亿月活用户的平台&#xff0c;其安全体系具有高度复杂性。未经优化的自动化工具面临极高封号风险&#xff1a;第一周35%、一个月65%、三个月85%、六个月95%。微信风控系统技术原理设备层防护 微信采集50设备特征参数&#xff0c;包括硬…

作者头像 李华
网站建设 2026/4/26 5:57:52

MyBatis/MyBatis-Plus类型转换器深度解析:从基础原理到自定义实践

目录前言基本概念一、TypeHandlerTypeHandler作用内置 TypeHandler 的自动映射二、jdbcType 的必要性&#xff1a;处理 NULL 值的核心三、自定义 TypeHandler前言 这篇博客主要讲一下mybatis/mybatisplus框架的类型转换器的相关知识和用法&#xff0c;最近项目有一个技术场景&…

作者头像 李华