简体   繁体   中英

how to close an overlay by clicking on outside in flutter

I'm creating an overlay onClick of a button, that is working fine from below code, but I want to close the overlay by clicking outside of it.

在此处输入图像描述

Reference code:

  • For creating overlay I'm using OverlayEntry

  • Setting the overlay position by using offset which is available when taped on any of the six buttons.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: GesturePositionDetector(),
    );
  }
}

class GesturePositionDetector extends StatelessWidget {
  OverlayState overlayState;
  OverlayEntry _overlayEntry;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              _getButtons([1, 2, 3], context),
              _getButtons([4, 5, 6], context),
              _getButtons([7, 8, 9], context)
            ],
          )),
    );
  }

  Widget _getButtons(List<int> labels, BuildContext context) {
    var listOfButtons = List<Widget>();

    labels.forEach((int label) {
      listOfButtons.add(_getButtonView('Button $label', context, label));
    });

    return Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: listOfButtons);
  }

  Widget _getButtonView(String label, BuildContext context, int index) {
    return GestureDetector(
      child: Container(
        height: 50,
        width: 150,
        margin : EdgeInsets.fromLTRB(15, 25, 15, 20),
        decoration: BoxDecoration(
            color: Colors.blueAccent,
            borderRadius: BorderRadius.all(Radius.circular(10))),
        child: Center(
          child: Text(
            label,
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
        ),
      ),
      onTapDown: (details) {
        onTap(details, context, index);
      },
    );
  }

  onTap(TapDownDetails details, context, int index) {
    var size = MediaQuery.of(context).size;
    var offset = details.globalPosition;

      _overlayEntry?.remove();
    overlayState = Overlay.of(context);

    _overlayEntry = new OverlayEntry(
        builder: (BuildContext context) => Positioned(
            left: offset.dx + 300 >= size.width ? offset.dx - 300 : offset.dx,
            top: offset.dy + 200 >= size.height ? offset.dy - 200 : offset.dy,
            child: Material(
              color: Colors.transparent,
              child: Container(
                  width: 300,
                  height: 200,
                  child: Container(
                      decoration: BoxDecoration(
                          color: Colors.white70,
                          borderRadius: BorderRadius.circular(20),
                          boxShadow: [
                            BoxShadow(
                              color: Colors.grey,
                              blurRadius: 5.0,
                            ),
                          ]),
                      margin: EdgeInsets.symmetric(horizontal: 20),
                      padding: EdgeInsets.fromLTRB(16, 10, 16, 10),
                      child: Wrap(
                        crossAxisAlignment: WrapCrossAlignment.center,
                        alignment: WrapAlignment.center,
                        direction: Axis.vertical,
                        spacing: 10,
                        children: <Widget>[
                          Text(
                            'Main Text',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 25),
                          ),
                          Text('sub text 1'),
                          Text('sub text 2'),
                          Text('sub text 3'),
                          Text('sub text 4')
                        ],
                      ))),
            )));
    overlayState.insert(_overlayEntry);
  }
}

Wrap the body with Gesture detector , On tap of body the tap event will fire, in tap event method close the overlay as shown in below code

Code:

body: GestureDetector(
  onTap: (){
    _overlayEntry?.remove();
  },
  child : Container(
  height: MediaQuery.of(context).size.height,
  width: MediaQuery.of(context).size.width,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM