You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:29:05