【问题标题】:Flutter remove OverlayEntry if touch outside如果触摸外部,则颤动删除 OverlayEntry
【发布时间】:2021-04-11 19:42:20
【问题描述】:

我有一个CustomDropDown,用OverlayEntry 完成。问题是我有一个StatefulWidget,我把它放在我的屏幕上,就像这样:

  CustomDropDownButton(
    buttonLabel: 'Aus Vorauswahl wählen',
    options: [
      '1',
      '2',
      '3',
      '4',
    ],
  ),

现在在CustomDropDownButton 里面,我可以简单地调用floatingDropdown.remove();,但我怎么能从父窗口小部件调用它呢?我希望你能理解我的问题。目前,移除overlay 的唯一方法是再次按下DropDownButton,但每次用户在实际叠加层之外点击时都应将其移除。

我在这里很迷茫,很高兴得到每一次帮助!如果您需要更多详细信息,请告诉我!

如果有帮助,这是我的CustomDropDownButton 的代码:

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

import '../../../constants/styles/colors.dart';
import '../../../constants/styles/text_styles.dart';
import '../../../services/size_service.dart';
import 'drop_down.dart';

class CustomDropDownButton extends StatefulWidget {
  String buttonLabel;
  final List<String> options;

  CustomDropDownButton({
    required this.buttonLabel,
    required this.options,
  });

  @override
  _CustomDropdownState createState() => _CustomDropdownState();
}

class _CustomDropdownState extends State<CustomDropDownButton> {
  late GlobalKey actionKey;
  late double height, width, xPosition, yPosition;
  bool _isDropdownOpened = false;
  int _selectedIndex = -1;
  late OverlayEntry floatingDropdown;

  @override
  void initState() {
    actionKey = LabeledGlobalKey(widget.buttonLabel);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      key: actionKey,
      onTap: () {
        setState(() {
          if (_isDropdownOpened) {
            floatingDropdown.remove();
          } else {
            findDropdownData();
            floatingDropdown = _createFloatingDropdown();
            Overlay.of(context)!.insert(floatingDropdown);
          }

          _isDropdownOpened = !_isDropdownOpened;
        });
      },
      child: Container(
        height: scaleWidth(50),
        decoration: BoxDecoration(
          border: Border(
            bottom: BorderSide(width: 1.0, color: AppColors.black),
          ),
          color: AppColors.white,
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            SizedBox(
              width: scaleWidth(10),
            ),
            Text(
              widget.buttonLabel,
              style: AppTextStyles.h5Light,
            ),
            Spacer(),
            _isDropdownOpened
                ? SvgPicture.asset(
                    'images/icons/arrow_down_primary.svg',
                    width: scaleWidth(21),
                  )
                : SvgPicture.asset(
                    'images/icons/arrow_up_primary.svg',
                    width: scaleWidth(21),
                  ),
            SizedBox(
              width: scaleWidth(10),
            ),
          ],
        ),
      ),
    );
  }

  void findDropdownData() {
    RenderBox renderBox =
        actionKey.currentContext!.findRenderObject()! as RenderBox;
    height = renderBox.size.height;
    width = renderBox.size.width;
    Offset? offset = renderBox.localToGlobal(Offset.zero);
    xPosition = offset.dx;
    yPosition = offset.dy;
  }

  OverlayEntry _createFloatingDropdown() {
    return OverlayEntry(builder: (context) {
      return Positioned(
        left: xPosition,
        width: width,
        top: yPosition + height,
        height: widget.options.length * height + scaleWidth(5),
        child: DropDown(
          itemHeight: height,
          options: widget.options,
          onOptionTap: (selectedIndex) {
            setState(() {
              widget.buttonLabel = widget.options[selectedIndex];
              _selectedIndex = selectedIndex;
              floatingDropdown.remove();
              _isDropdownOpened = !_isDropdownOpened;
            });
          },
          selectedIndex: _selectedIndex,
        ),
      );
    });
  }
}

【问题讨论】:

  • 我面临同样的问题。但是我还有一个问题,如果我导航到另一个页面,那么我们可以将 dispose() 方法覆盖为:@override void dispose() { floatingDropDown!.remove(); super.dispose(); } 希望这可能会有所帮助
  • 你能分享一下这个下拉列表的完整代码及其动态实现吗?

标签: flutter dart drop-down-menu state-management


【解决方案1】:

1.返回一个 ListView 而不是 GestureDetector 2。在 Listview 下,使用包含 DropDown 的 GestureDetector 作为子项之一。 3。添加另一个孩子(小部件)作为 GestureDetector 并将每个孩子的 onTap 设置为:

GestureDetector(
      onTap: () {
        if(isDropdownOpened){
          floatingDropDown!.remove();
          isDropdownOpened = false;
        }
      },
      child: Container(
        height: 200,
        color: Colors.black,
      ),
    )

简而言之,您必须将 GestureDetector 添加到您希望点击应关闭覆盖条目的任何位置

** 完整代码 **

//This is to close overlay when you navigate to another screen

 @override
  void dispose() {
    // TODO: implement dispose
    floatingDropDown!.remove();
    super.dispose();
  }


Widget build(BuildContext context) {
return ListView(
  children: [
    Padding(
      padding: EdgeInsets.all(20),
      child: GestureDetector(
        key: _actionKey,
        onTap: () {
          setState(() {
            if (isDropdownOpened) {
              floatingDropDown!.remove();
            } else {
              findDropDownData();
              floatingDropDown = _createFloatingDropDown();
              Overlay.of(context)!.insert(floatingDropDown!);
            }


            isDropdownOpened = !isDropdownOpened;
          });
        },
        child: Container(
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(8), color: Colors.orangeAccent),
          padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: Row(
            children: <Widget>[
              Text(
                widget.text,
                style: TextStyle(color: Colors.white, fontSize: 20),
              ),
              Spacer(),
              Icon(
                Icons.arrow_drop_down,
                color: Colors.white,
              ),
            ],
          ),
        ),
      ),
    ),
    GestureDetector(
      onTap: () {
        if(isDropdownOpened){
          floatingDropDown!.remove();
          isDropdownOpened = false;
        }
      },
      child: Container(
        height: 200,
        color: Colors.black,
      ),
    )
  ],
);

}

让我知道它是否有帮助

【讨论】:

    猜你喜欢
    • 2019-03-13
    • 1970-01-01
    • 1970-01-01
    • 2019-09-28
    • 2022-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-31
    相关资源
    最近更新 更多