如何实现Flutter App启动时弹出AlertDialog并在摇手机时关闭
实现Flutter启动时自动弹窗+摇晃关闭功能
这个需求挺有意思的,我来一步步帮你搞定:
1. 准备依赖
首先需要用到传感器包来检测手机摇晃,推荐用维护稳定的sensors_plus。在你的pubspec.yaml里添加依赖:
dependencies: flutter: sdk: flutter sensors_plus: ^4.0.1 # 可以替换为最新版本
然后运行flutter pub get完成安装。
2. 配置平台权限
为了保证在不同设备上正常运行,需要添加对应的平台配置:
- Android:在
android/app/src/main/AndroidManifest.xml里添加传感器声明(可选,但能提升兼容性):
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="false"/>
- iOS:在
ios/Runner/Info.plist里添加运动权限描述,避免App Store拒审:
<key>NSMotionUsageDescription</key> <string>需要检测手机摇晃来关闭弹窗</string>
3. 完整代码实现
下面是包含所有逻辑的完整示例,直接复制就能运行:
import 'package:flutter/material.dart'; import 'package:sensors_plus/sensors_plus.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Shake to Close Dialog', home: const ShakeDialogPage(), ); } } class ShakeDialogPage extends StatefulWidget { const ShakeDialogPage({super.key}); @override State<ShakeDialogPage> createState() => _ShakeDialogPageState(); } class _ShakeDialogPageState extends State<ShakeDialogPage> { bool _isDialogVisible = false; StreamSubscription? _accelerometerSubscription; // 摇晃阈值,数值越大需要摇晃的力度越强 final double _shakeThreshold = 15.0; @override void initState() { super.initState(); // 页面渲染完成后再弹窗,避免initState中context未就绪的问题 WidgetsBinding.instance.addPostFrameCallback((_) { _showStartupDialog(); }); // 启动传感器监听 _startShakeDetection(); } void _showStartupDialog() { setState(() { _isDialogVisible = true; }); showDialog( context: context, barrierDismissible: false, // 禁止点击空白关闭弹窗 builder: (context) => AlertDialog( title: const Text('欢迎使用!'), content: const Text('摇一摇你的手机就能关闭这个弹窗哦~'), actions: [ TextButton( onPressed: _closeDialog, child: const Text('手动关闭'), ), ], ), ).whenComplete(() { // 弹窗关闭后更新状态 setState(() { _isDialogVisible = false; }); }); } void _closeDialog() { if (_isDialogVisible) { Navigator.of(context).pop(); } } void _startShakeDetection() { _accelerometerSubscription = accelerometerEvents.listen((AccelerometerEvent event) { // 计算三轴加速度的绝对值之和,判断是否达到摇晃阈值 double totalAcceleration = event.x.abs() + event.y.abs() + event.z.abs(); if (totalAcceleration > _shakeThreshold && _isDialogVisible) { _closeDialog(); // 关闭弹窗后暂时取消监听,避免重复触发 _accelerometerSubscription?.cancel(); } }); } @override void dispose() { // 页面销毁时取消传感器订阅,防止内存泄漏 _accelerometerSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('摇晃关闭弹窗演示')), body: const Center( child: Text('启动时会自动弹出弹窗,摇一摇即可关闭'), ), ); } }
关键细节说明
- 启动弹窗时机:用
WidgetsBinding.instance.addPostFrameCallback确保页面渲染完成后再弹窗,避免initState阶段context未初始化的报错。 - 摇晃检测逻辑:通过监听加速度传感器事件,计算三轴加速度的绝对值之和,超过设定阈值就判定为摇晃。你可以根据需求调整
_shakeThreshold的数值。 - 资源管理:页面销毁时一定要取消传感器订阅,避免内存泄漏;弹窗关闭后暂时取消监听,防止用户后续摇晃误触发。
内容的提问来源于stack exchange,提问作者Mohamed Eldereny
相关产品推荐
相关产品推荐

