3

我想像这样摇动警报对话框:(不仅是文本,还有整个弹出对话框)

https://www.youtube.com/watch?v=IaHMoifUBSw

当用户单击按钮时,如何摇动整个警报对话框?

4

1 回答 1

3

这可以通过AnimatedBuilderTransform小部件来完成。使用sin函数 from将 to之间的值dart:math映射为具有所需幅度的平滑正弦波。周期可以直接使用本身指定。AnimationController0.01.0durationAnimationController

要启动动画,您可以调用controller.repeat()以使其无限期运行,直到您调用controller.stop(),或者您可以使用controller.forward()运行一次。

例如,让它摇动 3 次然后停止,您可以这样做:

onPressed: () async {
  await _controller.forward(from: 0.0);
  await _controller.forward(from: 0.0);
  await _controller.forward(from: 0.0);
},

这是它的实际效果(请注意 GIF 的帧速率限制):

演示 gif

下面附有完整的源代码供您用作起点。您可以调整durationdistance更改晃动动画的强度:

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Test(),
    );
  }
}

class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Shaking Dialog Demo')),
      body: Center(
        child: ElevatedButton(
          child: Text('Show Dialog'),
          onPressed: () {
            showDialog(
              context: context,
              builder: (_) => ShakeableDialog(),
            );
          },
        ),
      ),
    );
  }
}

class ShakeableDialog extends StatefulWidget {
  final Duration duration; // how fast to shake
  final double distance; // how far to shake

  const ShakeableDialog({
    Key? key,
    this.duration = const Duration(milliseconds: 300),
    this.distance = 24.0,
  }) : super(key: key);

  @override
  _ShakeableDialogState createState() => _ShakeableDialogState();
}

class _ShakeableDialogState extends State<ShakeableDialog>
    with SingleTickerProviderStateMixin {
  late final _controller = AnimationController(
    vsync: this,
    duration: widget.duration,
  );

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (BuildContext context, Widget? child) {
        final dx = sin(_controller.value * 2 * pi) * widget.distance;
        return Transform.translate(
          offset: Offset(dx, 0),
          child: child,
        );
      },
      child: AlertDialog(
        title: Text('Alert Dialog Title'),
        content: Text('Try these buttons!'),
        actions: [
          TextButton(
            child: Text('SHAKE 3 TIMES'),
            onPressed: () async {
              await _controller.forward(from: 0.0);
              await _controller.forward(from: 0.0);
              await _controller.forward(from: 0.0);
            },
          ),
          TextButton(
            child: Text('KEEP SHAKING'),
            onPressed: () => _controller.repeat(),
          ),
          TextButton(
            child: Text('STOP SHAKING'),
            onPressed: () => _controller.stop(),
          ),
          TextButton(
            child: Text('CLOSE'),
            onPressed: () => Navigator.of(context).pop(),
          ),
        ],
      ),
    );
  }
}
于 2021-10-09T06:44:58.240 回答