创建一个 toast 组件,不用任何包。

前言

竟可能的少依赖包,有些组件我们就可以自己写。

比如 Toast 提示组件,今天我们就自己实现一个。

原文 https://itnext.io/create-your-own-toast-without-using-any-packages-6d3828816f7c

正文

在 Flutter 中,创建覆盖窗口 widget 非常容易,所以让我向你展示实现覆盖窗口 widget 有多么容易!

MOTIVATION

context.showToast('Flutter is awesome!');

首先,要创建浮动 widget ,我们需要使用 Overlay widget 。

Overlay 是什么?

它只是一个类似 Stack 的 widget ,但 Overlay 是用来管理应用程序中页面顶部的 widget 的。就像一个特殊的堆栈,包装整个应用程序。

所以,基本上,如果我们添加一些东西到叠加的堆栈,它将出现在 UI 作为一个叠加,如果我们删除它,它将消失。仅此而已!

另外,最常见的是由导航器间接使用 Overlay 但是直接使用它也是可以的

让我们把逻辑看作一个代码,现在!

1. 用 CustomWidget 创建 OverlayEntry

要插入 Overlay 的堆栈,我们需要首先创建一个 OverlayEntry 对象

final myEntry = OverlayEntry(builder: (_) => CustomWidget());

2. 将 OverlayEntry 插入到 Overlay 的堆栈中

当我们插入 widget 时,Overlay 将在 UI 上显示 upmyEntry。

Overlay.of(context)!.insert(myEntry);

3. 从 Overlay 叠加堆栈中删除 verlayEntry 叠加条目!

当我们删除 myEntry 时,它将立即从 UI 中消失

myEntry.remove;

如果我们有主要的想法,让我们做一个 Toast widget ,现在!

Toast 例子

1. 设计一个 Toast

我还添加淡出动画与少量定制

// Just a simple toast wdiget with a simple fade animation, nothing more (valhalla)
class ToastWidget extends StatefulWidget {
  const ToastWidget({
    super.key,
    required this.text,
    this.duration = const Duration(seconds: 3),
    this.transitionDuration = const Duration(milliseconds: 250),
  });
  final String text;
  final Duration duration;
  final Duration transitionDuration;

  
  State<ToastWidget> createState() => _ToastWidgetState();
}

class _ToastWidgetState extends State<ToastWidget>
    with SingleTickerProviderStateMixin {
  late final AnimationController opacity;

  
  void initState() {
    super.initState();
    opacity = AnimationController(
      vsync: this,
      duration: widget.transitionDuration,
    )..forward();

    final startFadeOutAt = widget.duration - widget.transitionDuration;

    Future.delayed(startFadeOutAt, opacity.reverse);
  }

  
  void dispose() {
    opacity.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: opacity,
      child: Align(
        alignment: Alignment.bottomCenter,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.black.withOpacity(.65),
            borderRadius: const BorderRadius.all(Radius.circular(32)),
          ),
          margin: EdgeInsets.only(
            left: 16,
            right: 16,
            bottom: MediaQuery.of(context).size.height * .125,
          ),
          padding: const EdgeInsets.symmetric(
            horizontal: 24,
            vertical: 14,
          ),
          child: Text(
            widget.text,
            style: const TextStyle(
              fontSize: 14,
              color: Colors.white,
              decoration: TextDecoration.none,
              fontWeight: FontWeight.normal,
            ),
          ),
        ),
      ),
    );
  }
}

2. 为可重用代码创建 showToast 方法

为了让事情变得更简单,我把它变成了一种 扩展 extensions 。

extension ToastExtension on BuildContext {
  void showToast(
    String text, {
    Duration duration = const Duration(seconds: 3),
    Duration transitionDuration = const Duration(milliseconds: 250),
  }) {
    // Get the OverlayState
    final overlayState = Overlay.of(this);
    // Create an OverlayEntry with your custom widget
    final toast = OverlayEntry(
      builder: (_) => ToastWidget(
        text: text,
        transitionDuration: transitionDuration,
        duration: duration,
      ),
    );
    // then insert it to the overlay
    // this will show the toast widget on the screen
    overlayState!.insert(toast);
    // 3 secs later remove the toast from the stack
    // and this one will remove the toast from the screen
    Future.delayed(duration, toast.remove);
  }
}

3. 使用该方法显示来自任何地方的 Toast 信息

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.showToast('Flutter is awesome!'),
          child: const Text('Show Toast'),
        ),
      ),
    );
  }
}

最后

widget 树

如您所见,ToastWidget 并不依赖于 HomePage 或 ElevatedButton。这就是为什么,它不会受到影响,即使他们被处置。

代码

https://github.com/rei-codes/overlay_example

结束语

如果本文对你有帮助,请转发让更多的朋友阅读。

也许这个操作只要你 3 秒钟,对我来说是一个激励,感谢。

祝你有一个美好的一天~

猫哥课程


© 猫哥

  • 微信 ducafecat

  • https://wiki.ducafecat.tech

  • https://ducafecat.com

Last Updated:
Contributors: ducafecat