Search code examples
flutterdrop-down-menu

Toggle icon in an entry of dropdown menu while the dropdown is open


I am trying to display a list of files for playback and would like to allow the user to listen to them while selecting. I am using a DropdownButton to display the optional files. When the list is closed and i hit the play/stop icon, the icon is updated and displays correctly according to the state (playing/stopped). When the list is open the state is toggled but the icon doesnt get updated in the open list. How can i achieve this? I have tried using DropdownButton2 package. It is slightly better, it does updated the icon in the selected line but not next to any of the open items in the list.

import 'package:flutter/material.dart';

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

  static const routeName = '/';

  @override
  State<StatefulWidget> createState() => SampleItemListViewState();
}

class SampleItemListViewState extends State<SampleItemListView> {

  final List<String> items = const ['10', '20', '30'];
  bool isPlaying = false;
  String selectedItem = '10';

  @override
  void initState() {    
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample Items'),
      ),

      body: DropdownButtonFormField(
          value: selectedItem,
          onChanged: (value) async {
            selectedItem = value.toString();
          },
        items: items
          .map((e) => DropdownMenuItem(
          value: e,
          child: SizedBox(
              width: 100,
              child: Row(
                children: [
                  IconButton(
                    onPressed: () async {
                      setState(() {
                        isPlaying = !isPlaying;                                               
                      });
                    },
                    icon: isPlaying ? 
                      const Icon(Icons.stop_circle) : 
                      const Icon(Icons.play_arrow)),
                  const Spacer(),
                  Expanded(child: Text(e.toString())),
                ]
                )
            )))
            .toList(),
      ),
    );
  }
}


Solution

  • You can use StatefulBuilder because it has a own state and you can rebuild their local state

    class SampleItemListView extends StatefulWidget {
      const SampleItemListView({
        super.key,
      });
    
      static const routeName = '/';
    
      @override
      State<StatefulWidget> createState() => SampleItemListViewState();
    }
    
    class SampleItemListViewState extends State<SampleItemListView> {
      final List<String> items = const ['10', '20', '30'];
      bool isPlaying = false;
      String selectedItem = '10';
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Sample Items'),
          ),
          body: DropdownButtonFormField(
            value: selectedItem,
            onChanged: (value) async {
              selectedItem = value.toString();
            },
            items: items
                .map((e) => DropdownMenuItem(
                    value: e,
                    /// You can use StatefulBuilder
                    child: StatefulBuilder(builder: (context, menuState) {
                   return   SizedBox(
                          width: 100,
                          child: Row(children: [
                            IconButton(
                                onPressed: () async {
                                  menuState(() {
                                    isPlaying = !isPlaying;
                                  });
                                },
                                icon: isPlaying ? const Icon(Icons.stop_circle) : const Icon(Icons.play_arrow)),
                            const Spacer(),
                            Expanded(child: Text(e.toString())),
                          ]));
                    })))
                .toList(),
          ),
        );
      }
    }