Home > database >  Add custom dropdown on stack flutter
Add custom dropdown on stack flutter

Time:01-21

I'm trying to add a custom dropdown menu whose items are just links to other pages

I tried using DropdownButton

But I failed to make its elements as a link and it requires a value, and I do not have a value to pass to it

thank you

enter image description here

CodePudding user response:

You can use OverlayEntry for this case. Below is a simple working example of a dropdown using OverlayEntry:

class TestDropdownWidget extends StatefulWidget {
  TestDropdownWidget({Key? key}) : super(key: key);

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

class _TestDropdownWidgetState extends State<TestDropdownWidget>
    with TickerProviderStateMixin {
  final LayerLink _layerLink = LayerLink();
  late OverlayEntry _overlayEntry;
  bool _isOpen = false;

  //Controller Animation
  late AnimationController _animationController;
  late Animation<double> _expandAnimation;

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

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 200),
    );
    _expandAnimation = CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeInOut,
    );
  }

  @override
  Widget build(BuildContext context) {
    return CompositedTransformTarget(
      link: _layerLink,
      child: InkWell(
        onTap: _toggleDropdown,
        child: Text('Click Me'), //Define your child here
      ),
    );
  }

  OverlayEntry _createOverlayEntry() {
    return OverlayEntry(
      builder: (context) => GestureDetector(
        onTap: () => _toggleDropdown(close: true),
        behavior: HitTestBehavior.translucent,
        // full screen container to register taps anywhere and close drop down
        child: SizedBox(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: Stack(
            children: [
              Positioned(
                left: 100,
                top: 100.0,
                width: 250,
                child: CompositedTransformFollower(
                  //use offset to control where your dropdown appears
                  offset: Offset(0, 20),
                  link: _layerLink,
                  showWhenUnlinked: false,
                  child: Material(
                    elevation: 2,
                    borderRadius: BorderRadius.circular(6),
                    borderOnForeground: true,
                    color: Colors.white,
                    child: Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(6),
                        border: Border.all(color: Colors.grey),
                      ),
                      child: SizeTransition(
                        axisAlignment: 1,
                        sizeFactor: _expandAnimation,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.stretch,
                          children: [
                            //These are the options that appear in the dropdown
                            Text('Option 1'),
                            Text('Option 2'),
                            Text('Option 3'),
                            Text('Option 4'),
                            Text('Option 5'),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _toggleDropdown({
    bool close = false,
  }) async {
    if (_isOpen || close) {
      _animationController.reverse().then((value) {
        _overlayEntry.remove();
        if (mounted) {
          setState(() {
            _isOpen = false;
          });
        }
      });
    } else {
      _overlayEntry = _createOverlayEntry();
      Overlay.of(context)!.insert(_overlayEntry);
      setState(() => _isOpen = true);
      _animationController.forward();
    }
  }
}

Here's a gif to show the ui:

enter image description here

  • Related