Flutter/iOS中的Popover卡片效果:名称及Flutter实现可行性咨询
效果名称及Flutter实现方案
效果名称
这种交互效果通常被称为缩放式全屏模态页(Scaled Full-Screen Modal),属于可手势关闭的模态弹窗变体。核心表现为:打开新页面时,原页面轻微缩小并退至背景层,新页面几乎铺满屏幕;关闭时可通过下拉手势触发,同时原页面恢复至正常大小。
Flutter实现方案
完全可以在Flutter中实现该效果,以下是两种实用方案:
1. 基于showModalBottomSheet的自定义实现
通过配置showModalBottomSheet为接近全屏的高度,同时给原页面添加缩放动画,配合下拉手势关闭:
void _openScaledModal(BuildContext context) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (_) => GestureDetector( // 下拉距离足够时关闭模态页 onVerticalDragUpdate: (details) { if (details.delta.dy > 20) Navigator.pop(context); }, child: Container( height: MediaQuery.of(context).size.height * 0.95, decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: const Center(child: Text("模态页内容")), ), ), ); } // 原页面添加缩放效果 @override Widget build(BuildContext context) { final isModalOpen = ModalRoute.of(context)?.isCurrent == false; return Transform.scale( scale: isModalOpen ? 0.95 : 1.0, child: Scaffold( appBar: AppBar(title: const Text("主页面")), body: Center( child: ElevatedButton( onPressed: () => _openScaledModal(context), child: const Text("打开缩放模态页"), ), ), ), ); }
2. 自定义路由实现完整过渡动画
通过自定义PageRouteBuilder,同时控制原页面的缩放和新页面的滑入动画,效果更流畅:
class ScaledModalRoute extends PageRouteBuilder { final Widget modalPage; ScaledModalRoute({required this.modalPage}) : super( pageBuilder: (context, _, __) => modalPage, transitionsBuilder: (context, anim, secondaryAnim, child) { // 背景页面的缩放动画 final scaleTween = Tween<double>(begin: 1.0, end: 0.95).animate(secondaryAnim); // 新页面从底部滑入的动画 final slideTween = Tween<Offset>(begin: const Offset(0, 1), end: Offset.zero).animate(anim); return Stack( children: [ ScaleTransition(scale: scaleTween, child: ModalRoute.of(context)?.previousContentWidget), SlideTransition(position: slideTween, child: child), ], ); }, transitionDuration: const Duration(milliseconds: 300), ); } // 使用自定义路由打开模态页 Navigator.push(context, ScaledModalRoute(modalPage: const _ModalPage())); // 带下拉关闭的模态页 class _ModalPage extends StatelessWidget { const _ModalPage(); @override Widget build(BuildContext context) { return GestureDetector( onVerticalDragEnd: (details) { if (details.velocity.pixelsPerSecond.dy > 500) Navigator.pop(context); }, child: Scaffold( appBar: AppBar(title: const Text("全屏模态页")), body: const Center(child: Text("下拉即可关闭")), ), ); } }
内容的提问来源于stack exchange,提问作者DaraJ
相关产品推荐
相关产品推荐

