animated_custom_dropdown 2.0.0 copy "animated_custom_dropdown: ^2.0.0" to clipboard
animated_custom_dropdown: ^2.0.0 copied to clipboard

Custom dropdown widget allows to add highly customizable widget in your projects with proper open and close animations and also comes with form required validation.

example/lib/main.dart

import 'package:animated_custom_dropdown/custom_dropdown.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Custom Dropdown App',
      home: Home(),
    );
  }
}

const _labelStyle = TextStyle(fontWeight: FontWeight.w600);
const List<String> _list = [
  'Developer',
  'Designer',
  'Consultant',
  'Student',
];
const List<Job> _jobItems = [
  Job('Developer', Icons.developer_mode),
  Job('Designer', Icons.design_services),
  Job('Consultant', Icons.account_balance),
  Job('Student', Icons.school),
];

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

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[200],
      appBar: AppBar(
        systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
          statusBarColor: Colors.white,
        ),
        backgroundColor: Colors.white,
        elevation: .25,
        title: const Text(
          'Custom Dropdown Example',
          style: TextStyle(color: Colors.black, fontSize: 18),
        ),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16.0),
        children: [
          const Text('Job Roles Dropdown', style: _labelStyle),
          const SizedBox(height: 8),
          const SimpleDropDown(),
          const SizedBox(height: 24),
          const Divider(height: 0),
          const SizedBox(height: 24),

          // dropdown having search field
          const Text('Job Roles Search Dropdown', style: _labelStyle),
          const SizedBox(height: 8),
          const SearchDropDown(),
          const SizedBox(height: 24),
          const Divider(height: 0),
          const SizedBox(height: 24),

          // dropdown having search request field (making fake call)
          const Text('Job Roles Search Request Dropdown', style: _labelStyle),
          const SizedBox(height: 8),
          const SearchRequestDropDown(),
          const SizedBox(height: 24),
          const Divider(height: 0),
          const SizedBox(height: 24),

          const Text(
            'Job Roles Dropdown with Form validation',
            style: _labelStyle,
          ),
          const SizedBox(height: 8),
          ValidationDropDown(),
          const SizedBox(height: 24),
          const Divider(height: 0),
          const SizedBox(height: 24),

          const Text(
            'Awful, but fully customized search request with validation',
            style: _labelStyle,
          ),
          const SizedBox(height: 8),
          FullyCustomizedDropDown(),
          const SizedBox(height: 340),
        ],
      ),
    );
  }
}

class SimpleDropDown extends StatelessWidget {
  const SimpleDropDown({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomDropdown<String>(
      hintText: 'Select job role',
      items: _list,
      initialItem: _list[0],
      excludeSelected: false,
      onChanged: debugPrint,
    );
  }
}

class Job with CustomDropdownListFilter {
  final String name;
  final IconData icon;

  const Job(this.name, this.icon);

  @override
  String toString() {
    return name;
  }

  @override
  bool filter(String query) {
    return name.toLowerCase().contains(query.toLowerCase());
  }
}

class SearchDropDown extends StatelessWidget {
  const SearchDropDown({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomDropdown<Job>.search(
      hintText: 'Select job role',
      items: _jobItems,
      excludeSelected: true,
      onChanged: (value) {
        debugPrint('changing value to: $value');
      },
    );
  }
}

class SearchRequestDropDown extends StatelessWidget {
  const SearchRequestDropDown({Key? key}) : super(key: key);

  Future<List<Job>> getFakeRequestData(String query) async {
    return await Future.delayed(const Duration(seconds: 1), () {
      return _jobItems.where((e) {
        return e.name.toLowerCase().contains(query.toLowerCase());
      }).toList();
    });
  }

  @override
  Widget build(BuildContext context) {
    return CustomDropdown<Job>.searchRequest(
      futureRequest: getFakeRequestData,
      hintText: 'Search job role',
      excludeSelected: true,
      items: _jobItems,
      onChanged: (value) {
        debugPrint('changing value to: $value');
      },
    );
  }
}

class ValidationDropDown extends StatelessWidget {
  ValidationDropDown({Key? key}) : super(key: key);

  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          CustomDropdown<String>(
            hintText: 'Select job role',
            items: _list,
            excludeSelected: false,
            validateOnChange: true,
            onChanged: debugPrint,
            validator: (value) {
              if (value == null) {
                return "Must not be null";
              }
              return null;
            },
          ),
          const SizedBox(height: 16),
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              onPressed: () {
                if (!_formKey.currentState!.validate()) {
                  return;
                }
              },
              child: const Text(
                'Submit',
                style: TextStyle(fontWeight: FontWeight.w600),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class FullyCustomizedDropDown extends StatelessWidget {
  FullyCustomizedDropDown({Key? key}) : super(key: key);

  final _formKey = GlobalKey<FormState>();

  Future<List<Job>> _getFakeRequestData(String query) async {
    return await Future.delayed(const Duration(seconds: 1), () {
      return _jobItems.where((e) {
        return e.name.toLowerCase().contains(query.toLowerCase());
      }).toList();
    });
  }

  //function to be called with every item how it's gona be sho in the dropdown list
  Widget _listItemBuilder(BuildContext context, Job job) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [Text(job.name), Icon(job.icon)],
    );
  }

  //function to be called when a item is selected
  Widget _selectedHeaderBuilder(BuildContext context, Job job) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [Text(job.name)],
    );
  }

  //function to be called when a item is selected
  Widget _hintBuilder(BuildContext context, String hint) {
    return Row(
      children: [Text(hint), const Icon(Icons.question_mark)],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          CustomDropdown<Job>.searchRequest(
            futureRequest: _getFakeRequestData,
            items: _jobItems,
            futureRequestDelay: const Duration(milliseconds: 150),
            onChanged: (value) {
              debugPrint('changing value to: $value');
            },
            closedSuffixIcon: const Icon(Icons.account_balance),
            expandedSuffixIcon: const Icon(Icons.access_alarm),
            hintText: 'Select job role',
            excludeSelected: false,
            closedFillColor: Colors.pink,
            expandedFillColor: Colors.red[900],
            closedBorder: Border.all(
              color: Colors.black,
              width: 5,
            ),
            closedBorderRadius: BorderRadius.circular(15),
            expandedBorder: Border.all(
              color: Colors.orangeAccent,
              width: 5,
            ),
            expandedBorderRadius: BorderRadius.circular(5),
            listItemBuilder: _listItemBuilder,
            headerBuilder: _selectedHeaderBuilder,
            hintBuilder: _hintBuilder,
            closedErrorBorder: Border.all(color: Colors.blue, width: 10),
            closedErrorBorderRadius: BorderRadius.circular(15),
            errorStyle: const TextStyle(color: Colors.deepPurple, fontSize: 18),
            validateOnChange: true,
            validator: (value) {
              if (value == null) {
                return "Must not be null";
              }
              return null;
            },
          ),
          const SizedBox(height: 8),
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              onPressed: () {
                if (!_formKey.currentState!.validate()) return;
              },
              child: const Text(
                'Submit',
                style: TextStyle(fontWeight: FontWeight.w600),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
478
likes
150
points
13.6k
downloads
screenshot

Publisher

verified publisherabdullahchauhan.com

Weekly Downloads

Custom dropdown widget allows to add highly customizable widget in your projects with proper open and close animations and also comes with form required validation.

Repository (GitHub)
View/report issues

Topics

#ui #dropdown #spinner #widget

Documentation

API reference

Funding

Consider supporting this project:

buymeacoffee.com

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on animated_custom_dropdown