📜  Flutter – 实现叠加

📅  最后修改于: 2021-09-23 06:37:42             🧑  作者: Mango

Overlays 通过将它们插入到叠加层的 Stack 中,让独立的子小部件将视觉元素浮动在其他小部件的顶部。

本文讨论 Overlays 在Flutter的实现。为了实现覆盖在Flutter,我们需要知道大约两Flutter内置类OverlayEntry的Nd OverlayState 类

覆盖条目:

模糊地说 OverlayEntry 是 Overlay 中的一个地方,可以包含一个小部件。

OverlayEntry 类的构造函数:

OverlayEntry(
 {
  required WidgetBuilder builder,
  bool opaque = false,
  bool maintainState = false
 }
)

OverlayEntry 类的属性:

  • builder:需要一个小部件构建器。
  • 不透明:  采用一个布尔值来决定此条目是否遮挡整个叠加层。如果一个条目声称是不透明的,那么为了效率,覆盖将跳过在该条目下方构建条目,除非它们设置了维护状态
  • 维护状态:采用 bool 值,如果设置为 true,它会强制在不透明条目下方构建被遮挡的条目。

OverlayEntry 类的方法:

  • remove:从叠加层中删除此条目。

覆盖状态:

Overlay 的当前状态用于将 OverlayEntries 插入到覆盖层中。

OverlayState 类的方法:

  • debugIsVisible:检查给定的OverlayEntry是否可见并返回一个布尔值。
  • insert:将给定的OverlayEntry插入到 Overlay 中。
  • insertAll:获取一个OverlayEntries 列表并将所有条目插入到 Overlay 中。您还可以指定上面下面的属性来说明要插入的订单条目。
  • 重新排列:删除给定的 OverlayEntries 列表中列出的所有条目,然后按照给定的顺序将它们重新插入到叠加层中。  

我知道你对阅读理论不太感兴趣,所以让我们继续看一些例子。

示例 1:

Dart
import 'package:flutter/material.dart';
  
class Example1 extends StatefulWidget {
  const Example1({Key key}) : super(key: key);
  
  @override
  _Example1State createState() => _Example1State();
}
  
class _Example1State extends State {
  void _showOverlay(BuildContext context) async {
      
    // Declaring and Initializing OverlayState
    // and OverlayEntry objects
    OverlayState overlayState = Overlay.of(context);
    OverlayEntry overlayEntry;
    overlayEntry = OverlayEntry(builder: (context) {
        
      // You can return any widget you like here
      // to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.2,
        top: MediaQuery.of(context).size.height * 0.3,
        child: Container(
          width: MediaQuery.of(context).size.width * 0.8,
          child: Stack(
            children: [
              Image.asset(
                'images/commentCloud.png',
                colorBlendMode: BlendMode.multiply,
              ),
              Positioned(
                top: MediaQuery.of(context).size.height * 0.13,
                left: MediaQuery.of(context).size.width * 0.13,
                child: Row(
                  children: [
                    Material(
                      color: Colors.transparent,
                      child: Text(
                        'This is a button!',
                        style: TextStyle(
                            fontSize: MediaQuery.of(context).size.height * 0.03,
                            color: Colors.green),
                      ),
                    ),
                    SizedBox(
                      width: MediaQuery.of(context).size.width * 0.18,
                    ),
                    GestureDetector(
                      onTap: () {
                          
                        // When the icon is pressed the OverlayEntry
                        // is removed from Overlay
                        overlayEntry.remove();
                      },
                      child: Icon(Icons.close,
                          color: Colors.green,
                          size: MediaQuery.of(context).size.height * 0.025),
                    )
                  ],
                ),
              ),
            ],
          ),
        ),
      );
    });
  
    // Inserting the OverlayEntry into the Overlay
    overlayState.insert(overlayEntry);
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'GeeksForGeeks Example 2',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
      ),
      body: SafeArea(
          child: Center(
              child: MaterialButton(
        color: Colors.green,
        minWidth: MediaQuery.of(context).size.width * 0.4,
        height: MediaQuery.of(context).size.height * 0.06,
        child: Text(
          'show Overlay',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () {
          // calling the _showOverlay method 
          // when Button is pressed
          _showOverlay(context);
        },
      ))),
    );
  }
}


Dart
import 'package:flutter/material.dart';
  
class Example2 extends StatefulWidget {
  const Example2({Key key}) : super(key: key);
  
  @override
  _Example2State createState() => _Example2State();
}
  
class _Example2State extends State {
  void _showOverlay(BuildContext context) async {
      
    // Declaring and Initializing OverlayState
    // and OverlayEntry objects
    OverlayState overlayState = Overlay.of(context);
    OverlayEntry overlayEntry;
    overlayEntry = OverlayEntry(builder: (context) {
        
      // You can return any widget you like
      // here to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.2,
        top: MediaQuery.of(context).size.height * 0.3,
        child: Container(
          width: MediaQuery.of(context).size.width * 0.8,
          child: Stack(
            children: [
              Image.asset(
                'images/commentCloud.png',
                colorBlendMode: BlendMode.multiply,
              ),
              Positioned(
                top: MediaQuery.of(context).size.height * 0.13,
                left: MediaQuery.of(context).size.width * 0.13,
                child: Material(
                  color: Colors.transparent,
                  child: Text(
                    'I will disappear in 3 seconds.',
                    style: TextStyle(
                        fontSize: MediaQuery.of(context).size.height * 0.025,
                        color: Colors.green),
                  ),
                ),
              ),
            ],
          ),
        ),
      );
    });
  
    // Inserting the OverlayEntry into the Overlay
    overlayState.insert(overlayEntry);
  
    // Awaiting for 3 seconds
    await Future.delayed(Duration(seconds: 3));
  
    // Removing the OverlayEntry from the Overlay
    overlayEntry.remove();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'GeeksForGeeks Example 2',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
      ),
      body: SafeArea(
          child: Center(
              child: MaterialButton(
        color: Colors.green,
        minWidth: MediaQuery.of(context).size.width * 0.4,
        height: MediaQuery.of(context).size.height * 0.06,
        child: Text(
          'show Overlay',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () {
            
          // calling the _showOverlay method
          // when Button is pressed
          _showOverlay(context);
        },
      ))),
    );
  }
}


Dart
import 'package:flutter/material.dart';
  
class Example3 extends StatefulWidget {
  const Example3({Key key}) : super(key: key);
  
  @override
  _Example3State createState() => _Example3State();
}
  
class _Example3State extends State {
  void _showOverlay(BuildContext context) async {
      
    // Declaring and Initializing OverlayState and
    // OverlayEntry objects
    OverlayState overlayState = Overlay.of(context);
    OverlayEntry overlayEntry1;
    OverlayEntry overlayEntry2;
    OverlayEntry overlayEntry3;
    overlayEntry1 = OverlayEntry(builder: (context) {
        
      // You can return any widget you like here
      // to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.3,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Container(
            padding: EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
            width: MediaQuery.of(context).size.width * 0.8,
            height: MediaQuery.of(context).size.height * 0.1,
            color: Colors.pink.withOpacity(0.3),
            child: Material(
              color: Colors.transparent,
              child: Text('I will disappear in 3 seconds',
                  style: TextStyle(
                      fontSize: MediaQuery.of(context).size.height * 0.03,
                      fontWeight: FontWeight.bold,
                      color: Colors.white)),
            ),
          ),
        ),
      );
    });
    overlayEntry2 = OverlayEntry(builder: (context) {
        
      // You can return any widget you like here
      // to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.5,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Container(
            padding: EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
            width: MediaQuery.of(context).size.width * 0.8,
            height: MediaQuery.of(context).size.height * 0.1,
            color: Colors.blue.withOpacity(0.3),
            child: Material(
              color: Colors.transparent,
              child: Text('I will disappear in 5 seconds',
                  style: TextStyle(
                      fontSize: MediaQuery.of(context).size.height * 0.03,
                      fontWeight: FontWeight.bold,
                      color: Colors.white)),
            ),
          ),
        ),
      );
    });
    overlayEntry3 = OverlayEntry(builder: (context) {
        
      // You can return any widget you like 
      // here to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.7,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Container(
            padding: EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
            width: MediaQuery.of(context).size.width * 0.8,
            height: MediaQuery.of(context).size.height * 0.1,
            color: Colors.green.withOpacity(0.3),
            child: Material(
              color: Colors.transparent,
              child: Text('I will disappear in 7 seconds',
                  style: TextStyle(
                      fontSize: MediaQuery.of(context).size.height * 0.03,
                      fontWeight: FontWeight.bold,
                      color: Colors.white)),
            ),
          ),
        ),
      );
    });
  
    // Inserting the OverlayEntry into the Overlay
    overlayState.insertAll([overlayEntry1, overlayEntry2, overlayEntry3]);
  
    // Awaiting for 3 seconds
    await Future.delayed(Duration(seconds: 3));
  
    // Removing the first OverlayEntry from the Overlay
    overlayEntry1.remove();
  
    // Awaiting for 2 seconds more
    await Future.delayed(Duration(seconds: 2));
  
    // Removing the second OverlayEntry from the Overlay
    overlayEntry2.remove();
  
    // Awaiting for 2 seconds more
    await Future.delayed(Duration(seconds: 2));
  
    // Removing the third OverlayEntry from the Overlay
    overlayEntry3.remove();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'GeeksForGeeks Example 3',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
      ),
      body: SafeArea(
          child: Center(
              child: MaterialButton(
        color: Colors.green,
        minWidth: MediaQuery.of(context).size.width * 0.4,
        height: MediaQuery.of(context).size.height * 0.06,
        child: Text(
          'show Overlay',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () {
            
          //calling the _showOverlay method
          // when Button is pressed
          _showOverlay(context);
        },
      ))),
    );
  }
}


输出:

解释:

在这个flutter应用程序中,我在MaterialButtononPressed回调中调用了一个函数_showOverlay _showOverlay函数,我已经声明并初始化了OverlayStateOverlayEntry对象。在OverlayEntry 中,我传递了Comment Cloud的小部件,它有一个Text和一个Icon ,我用GestureDetector包裹了Icon ,在它的onTap回调中,我为OverlayEntry调用了remove函数,它从覆盖。您还可以让OverlayEntry在一段时间后自动移除,下一个示例解决了这个问题。在OverlayEntry初始化之后,我调用了OverlayState 的insert方法并传入了当前的OverlayEntry ,这会将Entry添加到Overlay 中

示例 2:

Dart

import 'package:flutter/material.dart';
  
class Example2 extends StatefulWidget {
  const Example2({Key key}) : super(key: key);
  
  @override
  _Example2State createState() => _Example2State();
}
  
class _Example2State extends State {
  void _showOverlay(BuildContext context) async {
      
    // Declaring and Initializing OverlayState
    // and OverlayEntry objects
    OverlayState overlayState = Overlay.of(context);
    OverlayEntry overlayEntry;
    overlayEntry = OverlayEntry(builder: (context) {
        
      // You can return any widget you like
      // here to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.2,
        top: MediaQuery.of(context).size.height * 0.3,
        child: Container(
          width: MediaQuery.of(context).size.width * 0.8,
          child: Stack(
            children: [
              Image.asset(
                'images/commentCloud.png',
                colorBlendMode: BlendMode.multiply,
              ),
              Positioned(
                top: MediaQuery.of(context).size.height * 0.13,
                left: MediaQuery.of(context).size.width * 0.13,
                child: Material(
                  color: Colors.transparent,
                  child: Text(
                    'I will disappear in 3 seconds.',
                    style: TextStyle(
                        fontSize: MediaQuery.of(context).size.height * 0.025,
                        color: Colors.green),
                  ),
                ),
              ),
            ],
          ),
        ),
      );
    });
  
    // Inserting the OverlayEntry into the Overlay
    overlayState.insert(overlayEntry);
  
    // Awaiting for 3 seconds
    await Future.delayed(Duration(seconds: 3));
  
    // Removing the OverlayEntry from the Overlay
    overlayEntry.remove();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'GeeksForGeeks Example 2',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
      ),
      body: SafeArea(
          child: Center(
              child: MaterialButton(
        color: Colors.green,
        minWidth: MediaQuery.of(context).size.width * 0.4,
        height: MediaQuery.of(context).size.height * 0.06,
        child: Text(
          'show Overlay',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () {
            
          // calling the _showOverlay method
          // when Button is pressed
          _showOverlay(context);
        },
      ))),
    );
  }
}

输出:

解释:

在这个例子中,我在MaterialButtononPressed回调中调用了一个函数_showOverlay 。在_showOverlay函数,我已经声明并初始化了OverlayStateOverlayEntry对象。在OverlayEntry 中,我传递了 Comment Cloud 的小部件,它显示了一个Text 。在OverlayEntry初始化之后,我调用了OverlayState 的insert方法并传入了当前的OverlayEntry ,这会将Entry添加到Overlay 中。之后,我在Future.delayed上等待https://github.com/curiousyuvi/overlay_implementation延迟 3 秒,然后调用remove方法从Overlay 中删除当前的OverlayEntry 。这会使条目出现 3 秒钟,然后消失。

示例 3:

Dart

import 'package:flutter/material.dart';
  
class Example3 extends StatefulWidget {
  const Example3({Key key}) : super(key: key);
  
  @override
  _Example3State createState() => _Example3State();
}
  
class _Example3State extends State {
  void _showOverlay(BuildContext context) async {
      
    // Declaring and Initializing OverlayState and
    // OverlayEntry objects
    OverlayState overlayState = Overlay.of(context);
    OverlayEntry overlayEntry1;
    OverlayEntry overlayEntry2;
    OverlayEntry overlayEntry3;
    overlayEntry1 = OverlayEntry(builder: (context) {
        
      // You can return any widget you like here
      // to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.3,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Container(
            padding: EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
            width: MediaQuery.of(context).size.width * 0.8,
            height: MediaQuery.of(context).size.height * 0.1,
            color: Colors.pink.withOpacity(0.3),
            child: Material(
              color: Colors.transparent,
              child: Text('I will disappear in 3 seconds',
                  style: TextStyle(
                      fontSize: MediaQuery.of(context).size.height * 0.03,
                      fontWeight: FontWeight.bold,
                      color: Colors.white)),
            ),
          ),
        ),
      );
    });
    overlayEntry2 = OverlayEntry(builder: (context) {
        
      // You can return any widget you like here
      // to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.5,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Container(
            padding: EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
            width: MediaQuery.of(context).size.width * 0.8,
            height: MediaQuery.of(context).size.height * 0.1,
            color: Colors.blue.withOpacity(0.3),
            child: Material(
              color: Colors.transparent,
              child: Text('I will disappear in 5 seconds',
                  style: TextStyle(
                      fontSize: MediaQuery.of(context).size.height * 0.03,
                      fontWeight: FontWeight.bold,
                      color: Colors.white)),
            ),
          ),
        ),
      );
    });
    overlayEntry3 = OverlayEntry(builder: (context) {
        
      // You can return any widget you like 
      // here to be displayed on the Overlay
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.7,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(20),
          child: Container(
            padding: EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
            width: MediaQuery.of(context).size.width * 0.8,
            height: MediaQuery.of(context).size.height * 0.1,
            color: Colors.green.withOpacity(0.3),
            child: Material(
              color: Colors.transparent,
              child: Text('I will disappear in 7 seconds',
                  style: TextStyle(
                      fontSize: MediaQuery.of(context).size.height * 0.03,
                      fontWeight: FontWeight.bold,
                      color: Colors.white)),
            ),
          ),
        ),
      );
    });
  
    // Inserting the OverlayEntry into the Overlay
    overlayState.insertAll([overlayEntry1, overlayEntry2, overlayEntry3]);
  
    // Awaiting for 3 seconds
    await Future.delayed(Duration(seconds: 3));
  
    // Removing the first OverlayEntry from the Overlay
    overlayEntry1.remove();
  
    // Awaiting for 2 seconds more
    await Future.delayed(Duration(seconds: 2));
  
    // Removing the second OverlayEntry from the Overlay
    overlayEntry2.remove();
  
    // Awaiting for 2 seconds more
    await Future.delayed(Duration(seconds: 2));
  
    // Removing the third OverlayEntry from the Overlay
    overlayEntry3.remove();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'GeeksForGeeks Example 3',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
      ),
      body: SafeArea(
          child: Center(
              child: MaterialButton(
        color: Colors.green,
        minWidth: MediaQuery.of(context).size.width * 0.4,
        height: MediaQuery.of(context).size.height * 0.06,
        child: Text(
          'show Overlay',
          style: TextStyle(color: Colors.white),
        ),
        onPressed: () {
            
          //calling the _showOverlay method
          // when Button is pressed
          _showOverlay(context);
        },
      ))),
    );
  }
}

输出:

解释:

在这个例子中,我在MaterialButtononPressed回调中调用了一个函数_showOverlay 。在_showOverlay函数,我声明并初始化了OverlayState和三个OverlayEntry对象。在这些OverlayEntries 中,我有不同颜色的Container并且它们都显示一个Text 。在OverlayEntries初始化之后,我为OverlayState调用了insertAll方法并传入了 OverlayEntries 列表,这会将所有条目添加到Overlay 中。之后,我等待Future.delayed延迟 3 秒,然后调用remove方法从Overlay 中删除第一个 OverlayEntry ,然后类似地我延迟了两秒钟,然后为第二个OverlayEntry调用了remove ,然后再次延迟了2 秒并为第三个也是最后一个OverlayEntry调用remove ,这使得OverlayEntries一个接一个消失。

想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!