OKToast 是一款 在 flutter 上 使用的 toast 插件

使用简单, 可定制性强, 纯 flutter, 调用不用 context

安装

查看文档: https://pub.dartlang.org/packages/oktoast#-installing-tab-

在 pubspec 引入

dependencies:
  oktoast: ^2.2.0 # 这一步请查询pub的最新版本

获取包: $ flutter packages get

引入: import 'package:oktoast/oktoast.dart';

使用

在代码中定义 OKToast 组件

包裹你的 MaterialApp,不是包裹你的 Scaffold
包裹你的 MaterialApp,不是包裹你的 Scaffold
包裹你的 MaterialApp,不是包裹你的 Scaffold

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return OKToast( // 这一步
      child: new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: new MyHomePage(),
      ),
    );
  }
}

这一步解释一下,因为一般情况下,一个 flutter 应用应该只有一个 MaterialApp(或是 WidgetsApp/CupertinoApp), 这里包裹后,可以缓存 Context 到 内存中,后续在调用显示时,不用传入 BuildContext

这样能满足一部分用户在无 context 的情况下调用 showToast 方法

调用

文本 toast

showToast("hello world");  // 可选属性看自己需求

20190418104706.png

自定义 widget

Widget widget = Center(
  child:Container(
      color:Colors.white,
      child:Icon(Icons.add),
  ),
);
showToastWidget(widget);

使用如下代码的效果


  void _showCustomWidgetToast() {
    var w = Center(
      child: Container(
        padding: const EdgeInsets.all(5),
        color: Colors.black.withOpacity(0.7),
        child: Row(
          children: <Widget>[
            Icon(
              Icons.add,
              color: Colors.white,
            ),
            Text(
              '添加成功',
              style: TextStyle(color: Colors.white),
            ),
          ],
          mainAxisSize: MainAxisSize.min,
        ),
      ),
    );
    showToastWidget(w);
  }

20190418104819.png

简单的 toast 实现

其实简单的方案,直接使用 Overlay 就可以了,不需要插件只需要一个简单的工具类,而且代码量并不大

class ToastHelper {
  static void showToast(BuildContext context, String text) {
    const style = TextStyle(color: Colors.white, fontSize: 14.0);

    Widget widget = Center(
      child: Container(
        color: Colors.black.withOpacity(0.5),
        padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
        child: Text(
          text,
          style: style,
        ),
      ),
    );
    var entry = OverlayEntry(
      builder: (_) => widget,
    );

    Overlay.of(context).insert(entry);

    Timer(const Duration(seconds: 2), () {
      entry?.remove();
    });
  }
}

那么为什么要用 OKToast 呢?

  1. 不用 context,方便一些在网络层的提示
  2. 比较方便的自定义,支持自建 widget
  3. 有一些小特性,比如软键盘弹出时自动移动位置防遮挡
  4. 支持手动隐藏 toast

进阶使用

隐藏已出现的 toast

有如下的方式可以隐藏

隐藏所有的 toast

手动隐藏:调用这个方法就可以关闭所有的 toast 了

dismissAllToast();

在显示 toast 时隐藏之前显示的所有 toast,其实是根据这个参数在方法内调用dismissAllToast

showToast("msg", dismissOtherToast: true);

全局设置隐藏之前的属性,这里设置后,每次当你显示新的 toast 时,旧的就会被关闭

OKToast(
  dismissOtherOnShow: true,
  ...
)

隐藏单独的 toast

每一个 showToast/showToastWidget 方法会有一个返回值,类型是 ToastFuture

var future = showToast("msg");
future.dismiss(); // 隐藏指定的toast

自定义属性

OKToast 组件有丰富的自定义属性

20190418102102.png

backgroundColor: 背景颜色

duration: 延迟隐藏时间

onDismiss: 隐藏时的回调

position: toast 的位置

radius: 圆角的尺寸

textAlign: 文字在内部的对齐方式

textDirection: ltr 或 rtl

textPadding: 文本距离边框的 padding

textStyle: 文本的样式

本文完整的 main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:oktoast/oktoast.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return OKToast(
      dismissOtherOnShow: true,
      child: new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          // This is the theme of your application.
          //
          // Try running your application with "flutter run". You'll see the
          // application has a blue toolbar. Then, without quitting the app, try
          // changing the primarySwatch below to Colors.green and then invoke
          // "hot reload" (press "r" in the console where you ran "flutter run",
          // or press Run > Flutter Hot Reload in IntelliJ). Notice that the
          // counter didn't reset back to zero; the application is not restarted.
          primarySwatch: Colors.blue,
        ),
        home: new MyHomePage(title: 'Flutter Demo Home Page'),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _showToast() {
    showToast("msg");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("OKToast示例"),
      ),
      body: ListView(
        children: <Widget>[
          RaisedButton(
            child: Text('文字toast'),
            onPressed: _showToast,
          ),
          RaisedButton(
            child: Text('自定义Widget Toast'),
            onPressed: _showCustomWidgetToast,
          ),
          RaisedButton(
            child: Text('ToastHelper '),
            onPressed: () => ToastHelper.showToast(context, "toast helper"),
          ),
        ],
      ),
    );
  }

  void _showCustomWidgetToast() {
    var w = Center(
      child: Container(
        padding: const EdgeInsets.all(5),
        color: Colors.black.withOpacity(0.7),
        child: Row(
          children: <Widget>[
            Icon(
              Icons.add,
              color: Colors.white,
            ),
            Text(
              '添加成功',
              style: TextStyle(color: Colors.white),
            ),
          ],
          mainAxisSize: MainAxisSize.min,
        ),
      ),
    );
    showToastWidget(w);
  }
}

class ToastHelper {
  static void showToast(BuildContext context, String text) {
    const style = TextStyle(color: Colors.white, fontSize: 14.0);

    Widget widget = Center(
      child: Material(
        child: Container(
          color: Colors.black.withOpacity(0.5),
          padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
          child: Text(
            text,
            style: style,
          ),
        ),
      ),
    );
    var entry = OverlayEntry(
      builder: (_) => widget,
    );

    Overlay.of(context).insert(entry);

    Timer(const Duration(seconds: 2), () {
      entry?.remove();
    });
  }
}

和 fluttertoast 的对比

为什么不使用 fluttertoast 呢, 我曾经也给 fluttertoast 提交过 PR

但是这个插件本身是依赖于原生的,android 端不可避免在默认样式上会受到 rom 的影响,并且各种属性会有兼容问题

我信奉的原则是,UI 层级的问题,直接在 flutter 端解决

后记

代码使用并不复杂, 如果对你有帮助解决了问题, 可以给我赞赏 ,请我喝咖啡(下方二维码)