flex_dropdown 0.2.0 copy "flex_dropdown: ^0.2.0" to clipboard
flex_dropdown: ^0.2.0 copied to clipboard

This package enables you to easily implement dropdowns with custom styling, animations, and data sources to match your app's needs.

example/lib/main.dart

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    super.key,
  });

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final OverlayPortalController _controller = OverlayPortalController();
  MenuPosition position = MenuPosition.bottomStart;
  bool dismissOnTapOutside = true;
  bool useButtonSize = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.onInverseSurface,
      appBar: AppBar(
        title: const Text('Flex Drop Down'),
      ),
      body: Column(
        children: [
          const SizedBox(height: 150),
          Align(
            alignment: Alignment.topCenter,
            child: Padding(
              padding: const EdgeInsets.only(top: 64.0),
              child: RawFlexDropDown(
                controller: _controller,
                menuPosition: position,
                dismissOnTapOutside: dismissOnTapOutside,
                buttonBuilder: (context, onTap) {
                  return ButtonWidget(
                    width: 400,
                    onTap: onTap,
                  );
                },
                menuBuilder: (context, width) {
                  return Padding(
                    padding: const EdgeInsets.only(top: 4),
                    child: MenuWidget(
                      width: useButtonSize ? width : 300,
                      onItemTap: () {
                        _controller.hide();
                      },
                    ),
                  );
                },
              ),
            ),
          ),
          const SizedBox(height: 250),
          Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text('Dismiss on tap outside'),
              const SizedBox(width: 8),
              Switch(
                value: dismissOnTapOutside,
                onChanged: (value) {
                  setState(() {
                    dismissOnTapOutside = value;
                  });
                },
              ),
              const SizedBox(width: 32),
              const Text('Use button size'),
              const SizedBox(width: 8),
              Switch(
                value: useButtonSize,
                onChanged: (value) {
                  setState(() {
                    useButtonSize = value;
                  });
                },
              ),
            ],
          ),
          const SizedBox(height: 32),
          Wrap(
            children: [
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    position = MenuPosition.bottomStart;
                  });
                },
                child: const Text("Bottom Left"),
              ),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    position = MenuPosition.bottomEnd;
                  });
                },
                child: const Text("Bottom Right"),
              ),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    position = MenuPosition.bottomCenter;
                  });
                },
                child: const Text("Bottom Center"),
              ),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    position = MenuPosition.topStart;
                  });
                },
                child: const Text("Top Left"),
              ),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    position = MenuPosition.topEnd;
                  });
                },
                child: const Text("Top Right"),
              ),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    position = MenuPosition.topCenter;
                  });
                },
                child: const Text("Top Center"),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class ButtonWidget extends StatelessWidget {
  const ButtonWidget({
    super.key,
    this.height = 48,
    this.width,
    this.onTap,
    this.child,
  });

  final double? height;
  final double? width;

  final VoidCallback? onTap;

  final Widget? child;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: height,
      width: width,
      child: Material(
        color: Colors.white,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10),
          side: const BorderSide(color: Colors.black12),
        ),
        child: InkWell(
          onTap: onTap,
          borderRadius: BorderRadius.circular(10),
          child: const Center(child: Text('Button')),
        ),
      ),
    );
  }
}

class MenuWidget extends StatelessWidget {
  const MenuWidget({
    super.key,
    this.width,
    required this.onItemTap,
  });

  final double? width;
  final VoidCallback onItemTap;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width,
      padding: const EdgeInsets.all(8),
      decoration: ShapeDecoration(
        color: Theme.of(context).colorScheme.primaryContainer,
        shape: RoundedRectangleBorder(
          side: const BorderSide(
            width: 1.5,
            color: Colors.black26,
          ),
          borderRadius: BorderRadius.circular(12),
        ),
        shadows: const [
          BoxShadow(
            color: Color(0x11000000),
            blurRadius: 32,
            offset: Offset(0, 20),
            spreadRadius: -8,
          ),
        ],
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Expanded(
                child: _FakeItemHolder(
                  text: 'Item 1',
                  onTap: onItemTap,
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                child: _FakeItemHolder(
                  text: 'Item 2',
                  onTap: onItemTap,
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            children: [
              Expanded(
                child: _FakeItemHolder(
                  text: 'Item 3',
                  onTap: onItemTap,
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                child: _FakeItemHolder(
                  text: 'Item 4',
                  onTap: onItemTap,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class _FakeItemHolder extends StatelessWidget {
  const _FakeItemHolder({
    required this.text,
    required this.onTap,
  });

  final String text;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return SizedBox(
      height: 80,
      child: Material(
        color: theme.colorScheme.onPrimary,
        shape: RoundedRectangleBorder(
          side: BorderSide(
            width: 1,
            color: theme.colorScheme.onSurfaceVariant,
          ),
          borderRadius: BorderRadius.circular(12),
        ),
        child: InkWell(
          borderRadius: BorderRadius.circular(12),
          onTap: onTap,
          child: Center(child: Text(text)),
        ),
      ),
    );
  }
}
9
likes
150
pub points
85%
popularity

Publisher

verified publishersnappx.io

This package enables you to easily implement dropdowns with custom styling, animations, and data sources to match your app's needs.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on flex_dropdown