开源鸿蒙跨平台Flutter开发:异性社交认知与神经递质测绘台_语言刺激与多巴胺奖
摘要: 本文基于神经生物学视角,将异性社交互动解构为神经递质调控系统,通过Flutter与HarmonyOS构建“社交认知测绘台”。系统模拟多巴胺(奖赏预测)、催产素(信任建立)、血清素(社交自信)和皮质醇(压力反应)的动态交互,采用数学模型(如RPE微分方程)量化社交策略的生化影响。通过UML架构实现状态分离,并运用CustomScrollView实现跨设备自适应布局,最终以雷达网络和流体动画可
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
演示效果



基于此种生命科学视域,本文将跨越传统话术的窠臼,将异性间的社交互动解构为一种“神经递质定向刺激工程”。依托于Flutter强大的渲染管线与HarmonyOS的跨设备协同能力,我们构建了一款独特的**“异性社交认知与神经递质测绘台”**。该测绘台通过数学模型模拟四大核心脑神经递质在不同语境策略下的动态演化,并以全定制UI和雷达网络的形式进行可视化反馈。
一、 社交语境与脑神经生化反应的数学建模
任何一种语言刺激输入到大脑听觉皮层后,都会迅速被杏仁核与前额叶皮层进行情绪解码,进而引发相关激素水平的变动。为了在代码中模拟这一过程,我们首先需要建立明确的生化指标矩阵。
1. 核心神经递质与社交状态映射表
| 生化指标 (神经递质) | 颜色代号 | 社交语境映射 | 演化阈值与触发条件 |
|---|---|---|---|
| 多巴胺 (Dopamine, DA) | 赛博青 | 探索欲、奖赏期待、情绪过山车 | 制造奖赏预测误差 (RPE) 时突增 |
| 催产素 (Oxytocin, OXT) | 催产粉 | 信任感、归属感、亲密剥露 | 深度共情与脆弱性暴露时释放 |
| 血清素 (Serotonin, 5-HT) | 稳定黄 | 框架稳定、社交自信、从容度 | 展现高价值或化解危机时维持高位 |
| 皮质醇 (Cortisol, COR) | 压力红 | 社交焦虑、防备心理、距离感 | 冷场或边界被侵犯时急速上升 |
2. 多巴胺奖赏预测误差模型 (KaTeX 推演)
在著名的多巴胺假说中,大脑并非对“奖赏本身”释放多巴胺,而是对“未知的奖赏预期”产生反应。这种机制被称为奖赏预测误差(Reward Prediction Error, RPE)。在异性社交的“推拉博弈(Push-Pull Dynamics)”中,这种生化机制表现得淋漓尽致。
我们可以用以下微分方程描述多巴胺浓度差值的变化:
Δ D A ( t ) = α ⋅ [ R ( t ) − V ( t ) ] + β ⋅ d S ( t ) d t \Delta DA(t) = \alpha \cdot \left[ R(t) - V(t) \right] + \beta \cdot \frac{dS(t)}{dt} ΔDA(t)=α⋅[R(t)−V(t)]+β⋅dtdS(t)
-
定义列表
- R ( t ) R(t) R(t):实际获得的社交反馈(如对方的笑容、赞同)。
- V ( t ) V(t) V(t):预期社交反馈。当预期很低,但实际反馈极高时, R ( t ) − V ( t ) > 0 R(t) - V(t) > 0 R(t)−V(t)>0,多巴胺暴增。
- S ( t ) S(t) S(t):语境刺激强度。
- α , β \alpha, \beta α,β:个体敏感度衰减系数。
在系统内,当用户选择“推拉博弈”策略时,我们会在后台算法中模拟这种预测差,瞬间拉高多巴胺靶向值,同时引发短期的皮质醇波动。
二、 测绘系统的架构解析 (UML图与流程拓扑)
为了实现从策略触发到底层生化数值变动,再到顶层UI重绘的闭环,应用采取了严格的状态分离架构。
1. 领域模型与类群关系 (UML Class Diagram)
2. 生化机能代谢与重绘生命周期 (Flowchart)
该系统不同于静态的数据面板,它包含一个“体内平衡(Homeostasis)”机制。任何激素的飙升都不会是永久的,必须有一个自发衰减并回归基线水平的过程。
三、 Flutter 核心工程代码推敲
在实现上述生化理论体系的过程中,代码的健壮性、界面的自适应性以及自定义渲染的性能把控至关重要。以下提取系统中的四大核心工程代码段落进行申论式剖析。
核心代码一:响应式安全视口与瀑布流坍缩架构
在大屏(HarmonyOS折叠屏或PC端)上,控制面板与波形雷达理应左右并列以达到最佳的信息展示密度;而一旦屏幕宽度遭遇收缩,如果不进行坍缩处理,横向布局将立刻引发致命的 RenderFlex Overflowed 异常。我们利用 CustomScrollView 重构了移动端的页面组织。
// 核心片段:动态视口坍缩管理
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
final isCompact = constraints.maxWidth < 1000;
if (isCompact) {
// 窄屏模式:启动 Sliver 瀑布流
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: SizedBox(
height: 450,
child: _buildVisualizer(isCompact: true), // 顶部显示生化雷达
),
),
SliverToBoxAdapter(
child: Container(height: 1, color: const Color(0xFF1E293B)),
),
SliverToBoxAdapter(
child: _buildControlPanel(), // 中部显示综合状态面板
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return _buildStrategyCard(_strategies[index]); // 底部展示话术策略列表
},
childCount: _strategies.length,
),
),
],
);
}
// 宽屏模式:使用 Row 和 Expanded 进行横向弹力分割 (代码略)
}
)
);
}
工程思辨:采用 Sliver 族群组件替代普通的 Column 包裹 ListView,是从根本上解决嵌套滚动视口高度无限膨胀(Unbounded Height Constraint)的银弹。SliverToBoxAdapter 完美充当了固定高度内容与动态列表之间的桥梁,保证了测绘图表在任何设备下都不会遭到意外裁剪。
核心代码二:基于生物体内平衡机制的阻尼衰减算法
如前文所述,人类的神经递质水平存在基线值(如皮质醇的基线偏高以维持警觉,催产素基线偏低)。任何通过“话术”带来的激素飙升或骤降,都必将面临随时间推移而被身体代谢掉的现实。这就要求我们的状态机必须内建一个代谢衰减(Decay)与阻尼追踪(Damping Tracking)的定时器机制。
// 核心片段:生化内平衡 (Homeostasis) 定时器逻辑
void initState() {
super.initState();
// ... 动画器初始化
_homeostasisTimer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
bool needsUpdate = false;
for (final tx in Neurotransmitter.values) {
// 动态获取基准代谢线
double baseValue = tx == Neurotransmitter.cortisol ? 0.3 : 0.2;
// 目标值不可抗拒地向基准值发生自然衰减
if (_targetLevels[tx]! > baseValue) {
_targetLevels[tx] = math.max(baseValue, _targetLevels[tx]! - 0.0005);
} else if (_targetLevels[tx]! < baseValue) {
_targetLevels[tx] = math.min(baseValue, _targetLevels[tx]! + 0.0005);
}
// 物理学阻尼平滑追踪:当前值逐步逼近目标值
if ((_currentLevels[tx]! - _targetLevels[tx]!).abs() > 0.001) {
_currentLevels[tx] = _currentLevels[tx]! + (_targetLevels[tx]! - _currentLevels[tx]!) * 0.08;
needsUpdate = true;
}
}
// 如果存在可见变化,则通知重绘
if (needsUpdate) {
setState(() {});
}
});
}
工程思辨:传统的状态赋值通常是离散的(即 current = target),这在UI上表现为数值生硬的跳变。我们在此引入 current += (target - current) * factor 公式,赋予了数值演化以真实的物理质量。加上极小步长的双边基线逼近算法,使得仪表盘上的液体槽和雷达图表现出犹如真实活体生物一般的“呼吸感”与“代谢感”。
核心代码三:多维生化指标雷达与突触放电渲染网络
在UI表现层,我们需要利用 CustomPainter 在极坐标系下绘制一个具有动态伸缩与呼吸发光特效的生化雷达,以直观展示多巴胺、催产素、血清素与皮质醇的博弈张力。
// 核心片段:雷达网络点阵渲染
void _drawRadarNetwork(Canvas canvas, Offset center, double radius) {
final int sides = Neurotransmitter.values.length;
final double angleStep = math.pi * 2 / sides;
final Path dataPath = Path();
final List<Offset> dataPoints = [];
for (int i = 0; i < sides; i++) {
final double angle = i * angleStep - math.pi / 2;
final Neurotransmitter tx = Neurotransmitter.values[i];
final double value = levels[tx]!;
// 映射当前浓度值到极坐标半径
final Offset dataPt = Offset(center.dx + math.cos(angle) * radius * value, center.dy + math.sin(angle) * radius * value);
dataPoints.add(dataPt);
if (i == 0) dataPath.moveTo(dataPt.dx, dataPt.dy);
else dataPath.lineTo(dataPt.dx, dataPt.dy);
}
dataPath.close();
// 渲染相连的神经突触路径
final strokePaint = Paint()
..color = const Color(0xFF00E5FF).withValues(alpha: 0.8)
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..strokeJoin = StrokeJoin.round;
canvas.drawPath(dataPath, strokePaint);
// 绘制伴随呼吸动画的高亮递质节点
for (int i = 0; i < dataPoints.length; i++) {
final tx = Neurotransmitter.values[i];
final pointPaint = Paint()
..color = tx.color
..style = PaintingStyle.fill
..maskFilter = const MaskFilter.blur(BlurStyle.solid, 4.0);
// 基于流体力学动画控制器的脉冲放大
final double pulse = 1.0 + math.sin(fluidProgress * math.pi * 2 + i) * 0.2;
canvas.drawCircle(dataPoints[i], 6.0 * pulse, pointPaint);
// 绘制由中心向外延伸的渐变神经光纤
final fiberPaint = Paint()
..shader = ui.Gradient.linear(center, dataPoints[i], [
tx.color.withValues(alpha: 0.0),
tx.color.withValues(alpha: 0.5),
])
..strokeWidth = 2.0;
canvas.drawLine(center, dataPoints[i], fiberPaint);
}
}
工程思辨:这段渲染代码深度整合了三角函数与路径规划(Path API)。MaskFilter.blur 被用来模拟神经元放电时的高斯模糊泛光效应;而 ui.Gradient.linear 构建的中心向外延伸的光纤,则隐喻了大脑中枢向下行神经传导指令的过程。
核心代码四:激素管柱的流体力学正弦模拟
仅仅展示二维的雷达网尚不足以表现生化激素那“涌动如潮”的特质。我们在屏幕边缘利用正弦函数(Sine Wave)结合动画时间偏移量,手摇出了一套逼真的“生化试管”波浪特效。
// 核心片段:试管内液体波浪模拟
void _drawFluidBars(Canvas canvas, Size size) {
final double barWidth = 15.0;
final double maxHeight = 120.0;
final double startY = size.height - 40;
for (int i = 0; i < Neurotransmitter.values.length; i++) {
final tx = Neurotransmitter.values[i];
final double val = levels[tx]!;
final double x = startX + i * 30.0;
// 当前激素槽的实际液面高度
final double fluidHeight = val * maxHeight;
// 手工绘制带有波浪顶部的流体路径
final Path fluidPath = Path();
final double waveStartY = startY - fluidHeight;
fluidPath.moveTo(x, startY);
fluidPath.lineTo(x + barWidth, startY);
fluidPath.lineTo(x + barWidth, waveStartY);
// 正弦差值模拟液面扰动
for(double dx = barWidth; dx >= 0; dx -= 1) {
// fluidProgress 作为时间轴推演参数
final double wy = waveStartY + math.sin((fluidProgress * math.pi * 2) + (dx * 0.5) + i) * 2.0;
fluidPath.lineTo(x + dx, wy);
}
fluidPath.close();
final fluidPaint = Paint()
..color = tx.color.withValues(alpha: 0.8)
..maskFilter = const MaskFilter.blur(BlurStyle.inner, 2.0); // 内部模糊增加液体透明质感
canvas.drawPath(fluidPath, fluidPaint);
}
}
工程思辨:这展示了 Flutter Canvas 在处理密集像素计算时的强大之处。我们没有使用任何笨重的 GIF 或者 Lottie 动画文件,而是仅仅依赖一个 for 循环与基础数学公式,就凭空捏造出了随着激素浓度高低而动态起伏的液体波浪。
四、 技术哲学视域下的社交解构
若是每一句精妙的赞美、每一次恰到好处的幽默,其最终目的都仅仅是为了诱发对方大脑边缘系统中区区几微克多巴胺分泌的“黑客指令”,那么爱情究竟是灵魂的共振,还是碳基生物的一场代码执行?
然而,正因为我们理解了这种底层机制的脆弱与必然,才使得我们在社交互动中具备了更高维度的宽容。当我们面临他人的冷漠退缩时,我们或许不再仅仅归咎于个人的魅力缺失,而是能理智地认识到:这不过是当下环境激发了对方过高的皮质醇防御水平。
科技的终极意义,往往在于用最冰冷的算法与物理指标,去丈量人类最为炽热、最为幽微的情感边界。这不仅仅是一段段运行在鸿蒙系统之上的 Dart 代码,它更是我们对生命科学与社交本质的一次深情致敬。
源代码
import 'dart:async';
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
DeviceOrientation.portraitUp,
]);
runApp(const SocialCognitionApp());
}
class SocialCognitionApp extends StatelessWidget {
const SocialCognitionApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '社交语境认知与神经递质测绘台',
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: const Color(0xFF070B19), // 极客深渊蓝
useMaterial3: true,
fontFamily: 'Roboto',
),
home: const SocialDashboard(),
);
}
}
// ==========================================
// 领域模型 (Domain Models - 生理神经与语境策略)
// ==========================================
enum Neurotransmitter {
dopamine, // 多巴胺:期待、奖赏、刺激
oxytocin, // 催产素:信任、亲密、共情
serotonin, // 血清素:状态自信、情绪稳定
cortisol, // 皮质醇:压力、紧张、警觉
}
extension NeurotransmitterExt on Neurotransmitter {
Color get color {
switch (this) {
case Neurotransmitter.dopamine:
return const Color(0xFF00E5FF); // 赛博青
case Neurotransmitter.oxytocin:
return const Color(0xFFFF1493); // 催产粉
case Neurotransmitter.serotonin:
return const Color(0xFFEAB308); // 稳定黄
case Neurotransmitter.cortisol:
return const Color(0xFFEF4444); // 压力红
}
}
String get label {
switch (this) {
case Neurotransmitter.dopamine:
return '多巴胺 (Dopamine)';
case Neurotransmitter.oxytocin:
return '催产素 (Oxytocin)';
case Neurotransmitter.serotonin:
return '血清素 (Serotonin)';
case Neurotransmitter.cortisol:
return '皮质醇 (Cortisol)';
}
}
}
class StrategyAction {
final String title;
final String description;
final Map<Neurotransmitter, double> impacts;
final IconData icon;
StrategyAction({
required this.title,
required this.description,
required this.impacts,
required this.icon,
});
}
// ==========================================
// 核心状态控制面板 (Main Dashboard)
// ==========================================
class SocialDashboard extends StatefulWidget {
const SocialDashboard({super.key});
@override
State<SocialDashboard> createState() => _SocialDashboardState();
}
class _SocialDashboardState extends State<SocialDashboard> with TickerProviderStateMixin {
late AnimationController _radarController;
late AnimationController _fluidController;
// 当前神经递质水平 (0.0 - 1.0)
final Map<Neurotransmitter, double> _currentLevels = {
Neurotransmitter.dopamine: 0.3,
Neurotransmitter.oxytocin: 0.2,
Neurotransmitter.serotonin: 0.4,
Neurotransmitter.cortisol: 0.6, // 初始带有一定防备压力
};
final Map<Neurotransmitter, double> _targetLevels = {
Neurotransmitter.dopamine: 0.3,
Neurotransmitter.oxytocin: 0.2,
Neurotransmitter.serotonin: 0.4,
Neurotransmitter.cortisol: 0.6,
};
Timer? _homeostasisTimer; // 体内平衡计时器
final List<StrategyAction> _strategies = [
StrategyAction(
title: '高情绪价值共情 (Deep Empathy)',
description: '精准识别对方情绪颗粒度,显著降低防备心理,建立初始信任机制。',
impacts: {
Neurotransmitter.oxytocin: 0.25,
Neurotransmitter.cortisol: -0.30,
Neurotransmitter.serotonin: 0.10,
},
icon: Icons.water_drop,
),
StrategyAction(
title: '推拉博弈 (Push-Pull Dynamics)',
description: '制造奖赏预测误差(RPE),激发探索欲与狩猎本能,快速拉升情绪过山车。',
impacts: {
Neurotransmitter.dopamine: 0.40,
Neurotransmitter.cortisol: 0.15, // 制造适度紧张
Neurotransmitter.oxytocin: -0.05,
},
icon: Icons.compare_arrows,
),
StrategyAction(
title: '脆弱性暴露 (Vulnerability Disclosure)',
description: '降维展示自身非核心缺陷,激发对方的保护欲与深度情感链接。',
impacts: {
Neurotransmitter.oxytocin: 0.35,
Neurotransmitter.serotonin: -0.10, // 自身状态略微下降
Neurotransmitter.dopamine: 0.10,
},
icon: Icons.favorite_border,
),
StrategyAction(
title: '幽默重塑 (Humorous Reframing)',
description: '通过认知失调与逻辑翻转,强制打破冷场,释放社交张力。',
impacts: {
Neurotransmitter.dopamine: 0.20,
Neurotransmitter.serotonin: 0.25,
Neurotransmitter.cortisol: -0.20,
},
icon: Icons.theater_comedy,
),
];
@override
void initState() {
super.initState();
_radarController = AnimationController(
vsync: this,
duration: const Duration(seconds: 10),
)..repeat();
_fluidController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat();
// 维持体内平衡(Homeostasis):缓慢向基础代谢值回归
_homeostasisTimer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
bool needsUpdate = false;
for (final tx in Neurotransmitter.values) {
// 基础代谢值
double baseValue = tx == Neurotransmitter.cortisol ? 0.3 : 0.2;
// 目标值自然衰减
if (_targetLevels[tx]! > baseValue) {
_targetLevels[tx] = math.max(baseValue, _targetLevels[tx]! - 0.0005);
} else if (_targetLevels[tx]! < baseValue) {
_targetLevels[tx] = math.min(baseValue, _targetLevels[tx]! + 0.0005);
}
// 阻尼追踪
if ((_currentLevels[tx]! - _targetLevels[tx]!).abs() > 0.001) {
_currentLevels[tx] = _currentLevels[tx]! + (_targetLevels[tx]! - _currentLevels[tx]!) * 0.08;
needsUpdate = true;
}
}
if (needsUpdate) {
setState(() {});
}
});
}
@override
void dispose() {
_radarController.dispose();
_fluidController.dispose();
_homeostasisTimer?.cancel();
super.dispose();
}
void _applyStrategy(StrategyAction action) {
setState(() {
action.impacts.forEach((tx, impact) {
_targetLevels[tx] = (_targetLevels[tx]! + impact).clamp(0.05, 1.0);
});
});
}
double _calculateOverallAttraction() {
// 综合吸引力指数模型 = 多巴胺 * 0.4 + 催产素 * 0.4 + 血清素 * 0.2 - 皮质醇 * 0.3
double score = (_currentLevels[Neurotransmitter.dopamine]! * 0.4) +
(_currentLevels[Neurotransmitter.oxytocin]! * 0.4) +
(_currentLevels[Neurotransmitter.serotonin]! * 0.2) -
(_currentLevels[Neurotransmitter.cortisol]! * 0.3);
return math.max(0.0, math.min(1.0, score + 0.2)); // 规范化到 0-1
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
final isCompact = constraints.maxWidth < 1000;
if (isCompact) {
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: SizedBox(
height: 450,
child: _buildVisualizer(isCompact: true),
),
),
SliverToBoxAdapter(
child: Container(height: 1, color: const Color(0xFF1E293B)),
),
SliverToBoxAdapter(
child: _buildControlPanel(),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return _buildStrategyCard(_strategies[index]);
},
childCount: _strategies.length,
),
),
],
);
}
return Row(
children: [
Expanded(
flex: 5,
child: Column(
children: [
_buildControlPanel(),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8),
itemCount: _strategies.length,
itemBuilder: (context, index) {
return _buildStrategyCard(_strategies[index]);
},
),
),
],
),
),
Container(width: 1, color: const Color(0xFF1E293B)),
Expanded(
flex: 6,
child: _buildVisualizer(isCompact: false),
),
],
);
},
),
);
}
Widget _buildControlPanel() {
final attraction = _calculateOverallAttraction();
final isDanger = _currentLevels[Neurotransmitter.cortisol]! > 0.7;
return Container(
color: const Color(0xFF030712),
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.psychology, color: Color(0xFF00E5FF), size: 32),
const SizedBox(width: 12),
const Text(
'神经递质反馈矩阵',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w900,
color: Colors.white,
letterSpacing: 2,
),
),
const Spacer(),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: isDanger ? const Color(0xFFEF4444).withValues(alpha: 0.2) : const Color(0xFF10B981).withValues(alpha: 0.2),
border: Border.all(color: isDanger ? const Color(0xFFEF4444) : const Color(0xFF10B981)),
borderRadius: BorderRadius.circular(4),
),
child: Text(
isDanger ? '防备阈值超限 (DEFENSE)' : '社交链路开启 (OPEN)',
style: TextStyle(
color: isDanger ? const Color(0xFFEF4444) : const Color(0xFF10B981),
fontWeight: FontWeight.bold,
fontSize: 12,
letterSpacing: 1,
),
),
),
],
),
const SizedBox(height: 32),
Text(
'综合吸引力指数 (Composite Attraction Index)',
style: TextStyle(
fontSize: 12,
color: Colors.grey[500],
fontWeight: FontWeight.bold,
letterSpacing: 1,
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: const Color(0xFF070B19),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFF1E293B)),
boxShadow: [
BoxShadow(
color: const Color(0xFF00E5FF).withValues(alpha: 0.05 + attraction * 0.15),
blurRadius: 20,
spreadRadius: -5,
)
],
),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
(attraction * 100).toStringAsFixed(1),
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.w900,
color: Color.lerp(const Color(0xFF64748B), const Color(0xFF00E5FF), attraction),
fontFamily: 'monospace',
),
),
const Padding(
padding: EdgeInsets.only(bottom: 10, left: 4),
child: Text(
'PTS',
style: TextStyle(
fontSize: 20,
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
),
const Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'心流状态预估',
style: TextStyle(
fontSize: 10,
color: Colors.grey[400],
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
attraction > 0.7 ? 'FLOW STATE ACHIEVED' : (attraction > 0.4 ? 'WARMING UP' : 'COLD DYNAMICS'),
style: TextStyle(
fontSize: 14,
color: attraction > 0.7 ? const Color(0xFFFF1493) : Colors.white,
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
],
),
],
),
const SizedBox(height: 16),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: attraction,
backgroundColor: const Color(0xFF0F172A),
valueColor: AlwaysStoppedAnimation<Color>(
Color.lerp(const Color(0xFF64748B), const Color(0xFF00E5FF), attraction)!,
),
minHeight: 6,
),
),
],
),
),
],
),
);
}
Widget _buildStrategyCard(StrategyAction action) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
child: InkWell(
onTap: () => _applyStrategy(action),
borderRadius: BorderRadius.circular(16),
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: const Color(0xFF0B1121),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFF1E293B)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: const Color(0xFF1E293B),
borderRadius: BorderRadius.circular(12),
),
child: Icon(action.icon, color: const Color(0xFF00E5FF), size: 20),
),
const SizedBox(width: 16),
Expanded(
child: Text(
action.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: const Color(0xFF3B82F6).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'STIMULUS INJECT',
style: TextStyle(
color: Color(0xFF60A5FA),
fontSize: 10,
fontWeight: FontWeight.bold,
fontFamily: 'monospace',
),
),
),
],
),
const SizedBox(height: 12),
Text(
action.description,
style: TextStyle(
fontSize: 12,
color: Colors.grey[400],
height: 1.5,
),
),
const SizedBox(height: 16),
// 展示影响条
Row(
children: action.impacts.entries.map((entry) {
final isPositive = entry.value > 0;
return Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Row(
children: [
Icon(
isPositive ? Icons.arrow_upward : Icons.arrow_downward,
size: 14,
color: entry.key.color,
),
const SizedBox(width: 4),
Text(
entry.key.name.substring(0, 3).toUpperCase(),
style: TextStyle(
color: entry.key.color,
fontSize: 12,
fontWeight: FontWeight.bold,
fontFamily: 'monospace',
),
),
],
),
);
}).toList(),
),
],
),
),
),
);
}
Widget _buildVisualizer({required bool isCompact}) {
return Container(
color: const Color(0xFF030712),
child: Stack(
children: [
// Background Matrix Grid
CustomPaint(
size: Size.infinite,
painter: DataMatrixPainter(),
),
// Fluid Bars & Radar
AnimatedBuilder(
animation: Listenable.merge([_radarController, _fluidController]),
builder: (context, child) {
return CustomPaint(
size: Size.infinite,
painter: NeuroNetworkPainter(
levels: _currentLevels,
radarProgress: _radarController.value,
fluidProgress: _fluidController.value,
),
);
},
),
],
),
);
}
}
// ==========================================
// 极客物理渲染:背景数据网格与神经网络生化渲染器
// ==========================================
class DataMatrixPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = const Color(0xFF1E293B).withValues(alpha: 0.3)
..strokeWidth = 1.0;
const double spacing = 40.0;
// Grid Lines
for (double i = 0; i < size.width; i += spacing) {
canvas.drawLine(Offset(i, 0), Offset(i, size.height), paint);
}
for (double i = 0; i < size.height; i += spacing) {
canvas.drawLine(Offset(0, i), Offset(size.width, i), paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
class NeuroNetworkPainter extends CustomPainter {
final Map<Neurotransmitter, double> levels;
final double radarProgress;
final double fluidProgress;
NeuroNetworkPainter({
required this.levels,
required this.radarProgress,
required this.fluidProgress,
});
@override
void paint(Canvas canvas, Size size) {
if (size.width <= 0 || size.height <= 0) return;
final centerX = size.width / 2;
final centerY = size.height / 2;
final center = Offset(centerX, centerY);
_drawRadarNetwork(canvas, center, math.min(size.width, size.height) * 0.35);
_drawFluidBars(canvas, size);
}
void _drawRadarNetwork(Canvas canvas, Offset center, double radius) {
// 绘制雷达图网格
final int sides = Neurotransmitter.values.length;
final double angleStep = math.pi * 2 / sides;
final gridPaint = Paint()
..color = const Color(0xFF334155).withValues(alpha: 0.5)
..style = PaintingStyle.stroke
..strokeWidth = 1.0;
// Draw concentric polygons
for (int step = 1; step <= 4; step++) {
final double r = radius * (step / 4);
final Path path = Path();
for (int i = 0; i < sides; i++) {
final double angle = i * angleStep - math.pi / 2;
final Offset pt = Offset(center.dx + math.cos(angle) * r, center.dy + math.sin(angle) * r);
if (i == 0) path.moveTo(pt.dx, pt.dy);
else path.lineTo(pt.dx, pt.dy);
}
path.close();
canvas.drawPath(path, gridPaint);
}
// Draw axis lines and calculate data points
final Path dataPath = Path();
final List<Offset> dataPoints = [];
for (int i = 0; i < sides; i++) {
final double angle = i * angleStep - math.pi / 2;
final Neurotransmitter tx = Neurotransmitter.values[i];
final double value = levels[tx]!;
// Axis line
final Offset endPt = Offset(center.dx + math.cos(angle) * radius, center.dy + math.sin(angle) * radius);
canvas.drawLine(center, endPt, gridPaint);
// Data point
final Offset dataPt = Offset(center.dx + math.cos(angle) * radius * value, center.dy + math.sin(angle) * radius * value);
dataPoints.add(dataPt);
if (i == 0) dataPath.moveTo(dataPt.dx, dataPt.dy);
else dataPath.lineTo(dataPt.dx, dataPt.dy);
// Label text
_drawText(canvas, tx.name.toUpperCase(), Offset(center.dx + math.cos(angle) * (radius + 20), center.dy + math.sin(angle) * (radius + 20)), tx.color);
}
dataPath.close();
// 缓慢旋转的背景发光
canvas.save();
canvas.translate(center.dx, center.dy);
canvas.rotate(radarProgress * math.pi * 2);
canvas.translate(-center.dx, -center.dy);
final fillPaint = Paint()
..color = const Color(0xFF00E5FF).withValues(alpha: 0.1)
..style = PaintingStyle.fill;
canvas.drawPath(dataPath, fillPaint);
canvas.restore();
// 绘制数据连线
final strokePaint = Paint()
..color = const Color(0xFF00E5FF).withValues(alpha: 0.8)
..style = PaintingStyle.stroke
..strokeWidth = 2.0
..strokeJoin = StrokeJoin.round;
canvas.drawPath(dataPath, strokePaint);
// 绘制高亮节点
for (int i = 0; i < dataPoints.length; i++) {
final tx = Neurotransmitter.values[i];
final pointPaint = Paint()
..color = tx.color
..style = PaintingStyle.fill
..maskFilter = const MaskFilter.blur(BlurStyle.solid, 4.0);
// 节点呼吸效果
final double pulse = 1.0 + math.sin(fluidProgress * math.pi * 2 + i) * 0.2;
canvas.drawCircle(dataPoints[i], 6.0 * pulse, pointPaint);
// 中心连接光纤
final fiberPaint = Paint()
..shader = ui.Gradient.linear(center, dataPoints[i], [
tx.color.withValues(alpha: 0.0),
tx.color.withValues(alpha: 0.5),
])
..strokeWidth = 2.0;
canvas.drawLine(center, dataPoints[i], fiberPaint);
}
}
void _drawFluidBars(Canvas canvas, Size size) {
// 在屏幕右下角/边缘绘制类似于医学试管的液体条
final double barWidth = 15.0;
final double maxHeight = 120.0;
final double spacing = 30.0;
final double startX = size.width - (Neurotransmitter.values.length * spacing) - 20;
final double startY = size.height - 40;
for (int i = 0; i < Neurotransmitter.values.length; i++) {
final tx = Neurotransmitter.values[i];
final double val = levels[tx]!;
final double x = startX + i * spacing;
// Draw container background
final bgPath = RRect.fromRectAndRadius(
Rect.fromLTWH(x, startY - maxHeight, barWidth, maxHeight),
const Radius.circular(4.0),
);
final bgPaint = Paint()..color = const Color(0xFF0F172A);
canvas.drawRRect(bgPath, bgPaint);
// Draw fluid value
final double fluidHeight = val * maxHeight;
// Simulate fluid wave
final Path fluidPath = Path();
final double waveStartY = startY - fluidHeight;
fluidPath.moveTo(x, startY);
fluidPath.lineTo(x + barWidth, startY);
fluidPath.lineTo(x + barWidth, waveStartY);
// Wave top
for(double dx = barWidth; dx >= 0; dx -= 1) {
final double wy = waveStartY + math.sin((fluidProgress * math.pi * 2) + (dx * 0.5) + i) * 2.0;
fluidPath.lineTo(x + dx, wy);
}
fluidPath.close();
final fluidPaint = Paint()
..color = tx.color.withValues(alpha: 0.8)
..maskFilter = const MaskFilter.blur(BlurStyle.inner, 2.0);
canvas.drawPath(fluidPath, fluidPaint);
// Draw Label
_drawText(canvas, tx.name.substring(0, 2).toUpperCase(), Offset(x + barWidth / 2, startY + 15), Colors.grey[500]!, fontSize: 10);
}
}
void _drawText(Canvas canvas, String text, Offset center, Color color, {double fontSize = 12}) {
final textSpan = TextSpan(
text: text,
style: TextStyle(
color: color,
fontSize: fontSize,
fontWeight: FontWeight.bold,
fontFamily: 'monospace',
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(canvas, Offset(center.dx - textPainter.width / 2, center.dy - textPainter.height / 2));
}
@override
bool shouldRepaint(covariant NeuroNetworkPainter oldDelegate) {
return oldDelegate.levels != levels ||
oldDelegate.radarProgress != radarProgress ||
oldDelegate.fluidProgress != fluidProgress;
}
}
更多推荐


所有评论(0)