求助:如何在Flutter中复现视频所示的showMenu交互行为?
实现思路与代码示例
可以用MouseRegion配合AnimatedContainer轻松实现这种悬停展开的交互效果,核心是通过鼠标进入/离开事件切换状态,触发容器的动画变化。以下是完整的可运行示例:
import 'package:flutter/material.dart'; void main() => runApp(const HoverCardDemo()); class HoverCardDemo extends StatelessWidget { const HoverCardDemo({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( backgroundColor: Colors.grey[100], body: Center( child: SizedBox( width: 300, child: HoverExpandCard( title: "Sample Card", subtitle: "Hover to see more details", expandedContent: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 12), Text( "Additional Information", style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox(height: 8), Text( "这里是悬停后显示的额外内容,可以是文本、图片或者任何Widget。" "你可以根据需求自定义这部分的布局和样式。", style: TextStyle(color: Colors.grey[700]), ), ], ), ), ), ), ), ); } } class HoverExpandCard extends StatefulWidget { final String title; final String subtitle; final Widget expandedContent; const HoverExpandCard({ super.key, required this.title, required this.subtitle, required this.expandedContent, }); @override State<HoverExpandCard> createState() => _HoverExpandCardState(); } class _HoverExpandCardState extends State<HoverExpandCard> { bool _isHovered = false; @override Widget build(BuildContext context) { return MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), child: AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(_isHovered ? 16 : 8), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(_isHovered ? 0.12 : 0.05), blurRadius: _isHovered ? 12 : 4, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( widget.title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( widget.subtitle, style: TextStyle(color: Colors.grey[600]), ), // 根据悬停状态显示/隐藏额外内容 if (_isHovered) widget.expandedContent, ], ), ), ); } }
关键部分说明
- MouseRegion:通过
onEnter和onExit回调更新_isHovered状态,这是触发交互的核心。 - AnimatedContainer:利用它的动画特性,在状态变化时自动过渡卡片的圆角、阴影等样式,实现平滑的视觉变化。
- 条件渲染:通过
if (_isHovered)控制额外内容的显示,配合容器动画完成展开效果。
额外优化建议
如果展开内容高度不确定,可以用AnimatedSize替代AnimatedContainer自动适配高度:
// 替换AnimatedContainer为AnimatedSize AnimatedSize( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, child: Container( // 保留原有的decoration、padding配置 child: Column(/* ... */), ), )
若内容过长,可在展开部分嵌套SingleChildScrollView避免布局溢出。
内容的提问来源于stack exchange,提问作者Danilo Souza
相关产品推荐
相关产品推荐

