Flutter 蒙层控件 ModalBarrier

1,592 阅读1分钟

ModalBarrier 是一个蒙层控件,可以对他后面的 UI 进行遮挡,阻止用户和后面的 UI 发生交互。

ModalBarrier 介绍

在实现上,核心代码是 是一个 ConstrainedBox 包了一个 ColoredBox 。ConstrainedBox 的作用是让 ModalBarrier 拥有允许范围内的最大尺寸。ColoredBox 就是画一个背景色。

ConstrainedBox(
       constraints: const BoxConstraints.expand(),
       child: color == null ? null : ColoredBox(
         color: color!,
       ),
     ),

参数主要有 3 个 color 设置背景色,dismissible 决定点击的时候是否隐藏,onDismiss 是一个回调,当隐藏的时候调用。

使用 ModalBarrier

使用 ModalBarrier 需要 用到 Stack,下面是一个例子。开始的时候 ModalBarrier 不显示,点击按钮的时候,显示 ModalBarrier,过几秒后自动消失。显示 ModalBarrier 的时候,尝试点击按钮,是点不到的,因为已经被 ModalBarrier 遮挡了。

class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  var showBarrier = false;

  @override
  void initState() {
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return SizedBox(
        width: 300,
        height: 300,
        child: Stack(
          alignment: Alignment.center,
          children: [
            ElevatedButton(
                onPressed: (() async {
                  setState(() {
                    showBarrier = true;
                  });
                  await Future.delayed(Duration(seconds: 5));
                  setState(() {
                    showBarrier = false;
                  });
                }),
                child: Text('显示 barrier')),
            if (showBarrier)
              ModalBarrier(
                color: Colors.black38,
              ),
          ],
        ));
  }
}

在这个例子中,你点遮罩,遮罩 是不消失的。因为让遮罩消失执行的代码是 Navigator.maybePop(context)。我们并没有 push ,所以 pop 也就没有反应了。

一般来说,如果想要全屏遮罩,直接用 Dialog 为好。想部分遮罩,才需要直接用 ModalBarrier,这个时候自己控制显隐。

 if (onDismiss != null) {
          onDismiss!();
        } else {
          Navigator.maybePop(context);
        }
  }

ModalBarrier 源码的逻辑是这样的,所以我们可以添加 onDismiss 回调,在回调函数里隐藏遮罩,这样就不会再走 Navigator.maybePop(context); 了。

ModalBarrier(
    dismissible: true,
    onDismiss: () {
      setState(() {
        showBarrier = false;
      });
    },
    color: Colors.black38,
  );