0

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

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much, but how to make it scrollable because the data is dynamic and I don't know the length of it
@Khalid use a ListView instead of Column for the options.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.