Flutter — реализация наложения

Опубликовано: 2 Сентября, 2022

Наложения позволяют независимым дочерним виджетам перемещать визуальные элементы поверх других виджетов, вставляя их в стек наложения.

В этой статье обсуждается реализация оверлеев во Flutter. Чтобы реализовать Overlay во Flutter, нам нужно знать о двух встроенных классах Flutter: классе OverlayEntry и классе Класс OverlayState .

Запись оверлея:

Расплывчато говоря, OverlayEntry — это место в оверлее, которое может содержать виджет.

Конструктор класса OverlayEntry:

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

Свойства класса OverlayEntry:

  • builder: принимает конструктор виджетов.
  • непрозрачный: Принимает логическое значение, определяющее, перекрывает ли эта запись все наложение. Если запись претендует на непрозрачность, то для эффективности оверлей будет пропускать записи построения ниже этой записи, если для них не установлен параметрmaintenateState.
  • MaintenanceState: принимает логическое значение, и если установлено значение true, принудительно строит закрытые записи ниже непрозрачной записи.

Методы класса OverlayEntry:

  • remove: удаляет эту запись из оверлея.

Состояние наложения:

Текущее состояние наложения используется для вставки элементов OverlayEntries в наложение.

Методы класса OverlayState:

  • debugIsVisible: проверяет, виден ли данный OverlayEntry или нет, и возвращает логическое значение.
  • вставка: вставляет данный OverlayEntry в оверлей.
  • insertAll: берет список OverlayEntries и вставляет все записи в Overlay. Вы также можете указать свойства выше и ниже , чтобы указать, в каком порядке должны быть вставлены записи.
  • переупорядочить: удалить все записи, перечисленные в заданном List of 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<Example1> {
  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);
        },
      ))),
    );
  }
}

Выход:

Объяснение:

В этом флаттер-приложении я вызвал функцию _showOverlay в обратном вызове onPressed для MaterialButton . В функции _showOverlay я объявил и инициализировал объекты OverlayState и OverlayEntry . В OverlayEntry я передал виджеты для облака комментариев , и у него есть текст и значок , я обернул значок с помощью GestureDetector и при его обратном вызове onTap я вызвал функцию удаления для OverlayEntry , которая удаляет эту запись из наложение. Вы также можете сделать так, чтобы OverlayEntry автоматически удалялся через определенное время, следующий пример посвящен этому. После инициализации OverlayEntry я вызвал метод вставки для OverlayState и передал текущий 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<Example2> {
  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);
        },
      ))),
    );
  }
}

Выход:

Объяснение:

В этом примере я вызвал функцию _showOverlay в обратном вызове onPressed для MaterialButton . В функции _showOverlay я объявил и инициализировал объекты OverlayState и OverlayEntry . В OverlayEntry я передал виджеты для облака комментариев, и он отображает текст . После инициализации OverlayEntry я вызвал метод вставки для OverlayState и передал текущий OverlayEntry , это добавляет Entry к Overlay . После этого у меня было https://github.com/curiousyuvi/overlay_implementation, ожидающее Future.delayed , чтобы сделать задержку в 3 секунды, а затем вызвать метод удаления , чтобы удалить текущий OverlayEntry из Overlay . В результате запись появляется на 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<Example3> {
  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(