0

I am developping an UI for the user to change the app language.

When showing the currently selected language I want to only display the flag with a dropdown icon. When the user clicks on the dropdown button I want the full string representation of the language to be added.

I can't seem to find a way to make the the selected item to look different than the menu items.

What I want: This for unopened dropdown: flag only, dropdown closed What I want: This for opened dropdown: flag and text, dropdown opened

Unwanted: flag only, dropdown opened Unwanted: flag and text, dropdown closed

I only get text for both or just flag for both, but never as desired.

The Code so far:

DropdownButton(
  items: LanguageUtils.getSupportedLanguagesAsStringList()
      .map<DropdownMenuItem<String>>((String langCodeString) {
    return DropdownMenuItem<String>(
      value: langCodeString,
      child: buildLanguageRowForDropDownButton(
          langCode:
              LanguageUtils.getLangCodeFromItsStringRep(langCodeString)),
    );
  }).toList(),
  value: LanguageUtils.getStringRepForLangCode(_chosenLangCode),
  onChanged: (String? value) {
    changeLanguage();
  },

);

/// Build row to be displayed in DropDownMenu.
Row buildLanguageRowForDropDownButton({LangCode? langCode}) {
  // Use currently _chosenLangCode as default.
  langCode = langCode ?? _chosenLangCode;

  // Build row from settings.
  List<Widget> rowElements = [];
  if (showFlag) {
    rowElements.add(getImageOfLangCode(langCode: langCode));
  }
  if (showWrittenLanguage) {
    rowElements
        .add(Text(LanguageUtils.getFullNameForLangCode(langCode)));
  }

  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: rowElements,
  );
}
// LanguageUtils

/// Functions around setting app translation language.
class LanguageUtils {
  LanguageUtils() {}

  /// Get written rep of language to display to user.
  static String getFullNameForLangCode(LangCode langCodeToGetStringFor) {
    switch (langCodeToGetStringFor) {
      case LangCode.en:
        return "English";
        break;
      case LangCode.de:
        return "Deutsch";
        break;
    }
  }

  /// Get short rep of language code to use programmatically when exporting state.
  static String getStringRepForLangCode(LangCode langCodeToGetStringFor) {
    switch (langCodeToGetStringFor) {
      case LangCode.en:
        return "en";
        break;
      case LangCode.de:
        return "de";
        break;
    }
  }

  /// Get all supported LangCodes as string rep to create dropdown menu from.
  static List<String> getSupportedLanguagesAsStringList() {
    return LangCode.values.map((e) => e.name).toList();
  }

  /// To return LangCode from its converted rep.
  ///
  /// Defaults to en => Failsafe, always returns valid LangCode.
  static LangCode getLangCodeFromItsStringRep(String langCodeAsString) {
    switch (langCodeAsString) {
      case "de":
        return LangCode.de;
        break;

      case "en":
      default:
        return LangCode.en;
        break;
    }
  }
}

/// Supported Languages.
enum LangCode { en, de }

I looked at flutter dev, searched stackoverflow, googled and attempted to change things on my own.

Patrick Michiels
  • 239
  • 4
  • 13

1 Answers1

2

Looks like you need to use the selectedItemBuilder of DropdownButton.

Here's an example you can try and plug in your data to get the desired output:

import 'package:flutter/material.dart';

const List<String> list = <String>['One  ', 'Two ', 'Three', 'Four'];

void main() => runApp(const DropdownButtonApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('DropdownButton Sample')),
        body: const Center(
          child: DropdownButtonExample(),
        ),
      ),
    );
  }
}

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

  @override
  State<DropdownButtonExample> createState() => _DropdownButtonExampleState();
}

class _DropdownButtonExampleState extends State<DropdownButtonExample> {
  String dropdownValue = list.first;

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      value: dropdownValue,
      //icon: const Icon(Icons.arrow_downward),
      elevation: 16,
      style: const TextStyle(color: Colors.deepPurple),
      underline: Container(
        height: 2,
        color: Colors.deepPurpleAccent,
      ),
      onChanged: (String? value) {
        // This is called when the user selects an item.
        setState(() {
          dropdownValue = value!;
        });
      },

      selectedItemBuilder: (context) =>
          List.generate(1,
                        (i) => 
                       const SizedBox(
                        width: 50,
                        child: Icon(Icons.flag)
                        )
                       ),
     
      items: list.map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: SizedBox(
            width: 100,
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: [const Icon(Icons.flag), Text(value)],
            ),
          ),
        );
      }).toList(),
    );
  }
}

Note: SizedBox is important so it doesn't throw viewport errors.

Clevino Alrin
  • 204
  • 2
  • 9