GithubHelp home page GithubHelp logo

Comments (13)

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024 1

same idea :)

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

  @override
  State<MyDropdownButton> createState() => _MyDropdownButtonState();
}

class _MyDropdownButtonState extends State<MyDropdownButton> {
  final List<String> customers = [
    'Customer 1',
    'Customer 2',
  ];

  String? selectedCustomer;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          margin: const EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 0.0),
          child: InputDecorator(
            decoration: InputDecoration(
              filled: true,
              fillColor: Colors.teal.shade50,
              contentPadding: const EdgeInsets.symmetric(horizontal: 20),
              enabledBorder: OutlineInputBorder(
                borderSide: BorderSide(
                  color: Colors.teal.shade800,
                ),
              ),
              label: Text(
                'Customer',
                style: TextStyle(
                  color: Colors.teal.shade800,
                ),
              ),
            ),
            child: DropdownButtonHideUnderline(
              child: DropdownButton2<String>(
                buttonPadding: const EdgeInsets.symmetric(vertical: 6),
                itemPadding: const EdgeInsets.symmetric(horizontal: 20),
                dropdownWidth: MediaQuery.of(context).size.width -
                    (8.0 + 8.0), //L&R container's margin
                offset: const Offset(-20, 0),
                hint: Text(
                  'Select customer',
                  style: TextStyle(
                    color: Colors.teal.shade800,
                  ),
                ),
                style: const TextStyle(
                  color: Colors.black,
                ),
                selectedItemBuilder: (context) {
                  return customers.map((element) {
                    return Align(
                      alignment: Alignment.centerLeft,
                      child: Text(
                        element,
                        style: TextStyle(
                          color: Colors.teal.shade800,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    );
                  }).toList();
                },
                icon: Icon(
                  Icons.arrow_drop_down,
                  color: Colors.teal.shade800,
                ),
                items: customers
                    .map((item) => DropdownMenuItem<String>(
                          value: item,
                          child: Text(
                            item,
                            style: const TextStyle(
                              fontSize: 14,
                            ),
                          ),
                        ))
                    .toList(),
                isExpanded: true,
                value: selectedCustomer,
                onChanged: (value) {
                  setState(() => selectedCustomer = value);
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024 1

When both buttonWidth & dropdownWidth is null (not used), their width will be calculated from the maximum width of items or hint text IndexedStack.
Therefore, MenuHorizontalPadding (itemPadding+dropdownPadding+dropdownScrollPadding) need to be added to that IndexedStack so Both button and menu Adapt to max items width when buttonWidth & dropdownWidth is null.

so that behavior is necessary for another use case not yours. Adding any dropdownWidth value for your case will prevent adding that default MenuHorizontalPadding. but you need your dropdown menu to be equal to the button which in your case is screen size - 16.0 (right and left margin).

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024 1

All that tricky work is necessary because of the need to add contentPadding in your case. which is added to the InputDecorator around the DropdownButton2 so you need to manually consider it with dropdown width too :)

from dropdown_button2.

ShahoodulHassan avatar ShahoodulHassan commented on June 23, 2024 1

After having a better clarity on these concepts, I've further finetuned the UI by adding an icon on the left of the DropdownButton2 widget. 'dropdownWidth' had to be made dependent on the width of InputDecorator this time, instead of the width retrieved from MediaQuery. Here is the final result:

Screenshot 2022-12-09 000445

I must say I've learned a lot about this widget today and I'll be way more confident and comfortable using it in future. Thanks a lot for taking time to explain the underlying concepts and providing a fix suitable to my particular use case.

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024

Wrap your label with padding:

label: Padding(
      padding: EdgeInsets.only(left: 20.0),
      child: Text('hello'),
    ),

from dropdown_button2.

ShahoodulHassan avatar ShahoodulHassan commented on June 23, 2024

I've tried this as well but then there is a huge gap between the label and the outline border on the left. It looks even more awkward.

Screenshot 2022-12-08 174606_054639

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024

That's correct.
Well, That's the default behavior of InputDecoration and this is related to flutter.
You can use floatingLabelAlignment to align label to center instead but It's not possible to set padding for the label without affecting the hint/contents.

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024

Btw, as you have padding for the contents anyway, why not using contentPadding of left and only use right padding for the hint/contents ?

from dropdown_button2.

ShahoodulHassan avatar ShahoodulHassan commented on June 23, 2024

Btw, as you have padding for the contents anyway, why not using contentPadding of left and only use right padding for the hint/contents ?

I don't think I understood this properly.

Anyway, here is my content padding in the InputDecorator -> contentPadding: EdgeInsets.zero, and here is my button padding in DropdownButton2 -> buttonPadding: const EdgeInsets.fromLTRB(0, 6, 6, 6)

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024

Can you share a small sample code ?

from dropdown_button2.

AhmedLSayed9 avatar AhmedLSayed9 commented on June 23, 2024

Here's an example (hence: contentPadding, itemPadding, dropdownWidth and offset properties):

final List<String> genderItems = [
  'Male',
  'Female',
];

String? selectedValue;

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: SizedBox(
        width: 300,
        child: DropdownButtonFormField2(
          decoration: InputDecoration(
            isDense: true,
            label: const Text("Label"),
            contentPadding: const EdgeInsets.symmetric(horizontal: 20),
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(15),
            ),
          ),
          hint: const Text(
            'Select Your Gender',
            style: TextStyle(fontSize: 14),
          ),
          icon: const Icon(
            Icons.arrow_drop_down,
            color: Colors.black45,
          ),
          buttonHeight: 60,
          itemPadding: const EdgeInsets.only(left: 20),
          dropdownWidth: 300,
          offset: const Offset(-20, 0),
          items: genderItems
              .map((item) => DropdownMenuItem<String>(
                    value: item,
                    child: Text(
                      item,
                      style: const TextStyle(
                        fontSize: 14,
                      ),
                    ),
                  ))
              .toList(),
          onChanged: (value) {
            //Do something when changing the item if you want.
          },
        ),
      ),
    ),
  );
}

from dropdown_button2.

ShahoodulHassan avatar ShahoodulHassan commented on June 23, 2024

Can you share a small sample code ?

I've created this widget as a sample taking the same properties as that in my actual code.

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

  @override
  State<MyDropdownButton> createState() => _MyDropdownButtonState();
}

class _MyDropdownButtonState extends State<MyDropdownButton> {
  final List<String> customers = [
    'Customer 1',
    'Customer 2',
  ];

  String? selectedCustomer;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 0.0),
      child: Expanded(
        child: InputDecorator(
          decoration: InputDecoration(
            filled: true,
            fillColor: Colors.teal.shade50,
            contentPadding: EdgeInsets.zero,
            enabledBorder: OutlineInputBorder(
              borderSide: BorderSide(
                color: Colors.teal.shade800,
              ),
            ),
            label: Padding(
              padding: const EdgeInsets.only(left: 20.0),
              child: Text(
                'Customer',
                style: TextStyle(
                  color: Colors.teal.shade800,
                ),
              ),
            ),
          ),
          child: DropdownButtonHideUnderline(
            child: DropdownButton2<String>(
              buttonPadding: const EdgeInsets.fromLTRB(0, 6, 6, 6),
              hint: Text(
                'Select customer',
                style: TextStyle(
                  color: Colors.teal.shade800,
                ),
              ),
              style: const TextStyle(
                color: Colors.black,
              ),
              selectedItemBuilder: (context) {
                return customers.map((element) {
                  return Align(
                    alignment: Alignment.centerLeft,
                    child: Text(
                      element,
                      style: TextStyle(
                        color: Colors.teal.shade800,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  );
                }).toList();
              },
              icon: Icon(
                Icons.arrow_drop_down,
                color: Colors.teal.shade800,
              ),
              items: customers
                  .map((item) => DropdownMenuItem<String>(
                        value: item,
                        child: Text(
                          item,
                          style: const TextStyle(
                            fontSize: 14,
                          ),
                        ),
                      ))
                  .toList(),
              isExpanded: true,
              value: selectedCustomer,
              onChanged: (value) {
                setState(() => selectedCustomer = value);
              },
            ),
          ),
        ),
      ),
    );
  }
}

from dropdown_button2.

ShahoodulHassan avatar ShahoodulHassan commented on June 23, 2024

Awesome!
As far as I can understand, dropdownWidth and offset made all the difference here.

However, just out of curiosity, if in above code, I remove dropdownWidth and offset, I get the following result. This is something that I kept struggling with without knowing why the contents of the button ('Select customer', in this case) were being wrongly aligned. Is button's width somehow linked with the dropdownWidth?

Screenshot 2022-12-08 223854

from dropdown_button2.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.