How to deselected other buttons when a button is selected?

230

I'd need more code to answer accurately.

However, one solution is to lift up the state.

In Flutter, it makes sense to keep the state above the widgets that use it.

So the StatefulWidget that render the GraphSpot can have a _selectedIndex property that holds the selected index. Then you can pass an onGraphSpotTap function to each GraphSpot Widget.

int? _selectedIndex;
 
List<GraphSpot> spots = spotsXPos.mapIndexed<GraphSpot>((record, index) {
  return GraphSpot(
    x: record['xPos'],
    y: record['yPos'],
    date: record['record_date'],
    weight: record['weight'],
    id: index,
    selected: index == _selectedIndex ? true : false,
    onGraphSpotTap: () {
        setState(() {
          _selectedIndex = index;
        });
      }

         );
}).toList();

Then in your GraphSpot add the new onGraphSpotTap property.

class GraphSpot extends StatelessWidget {
  .....
  final VoidCallback? onGraphSpotTap;

  ....
  onTap: onGraphSpotTap

Don't forget to modify the GraphSpot Widget rendering based on its selected property

Share:
230
João Pedro
Author by

João Pedro

Updated on December 30, 2022

Comments

  • João Pedro
    João Pedro over 1 year

    I'm building a line graph and the spots can be edited by selecting them, however, I want the spots to work like radio buttons, only one can be selected at a time. I can't get it to work right now:

    enter image description here

    the graph is rendered by fetching data from SQflite and then I use Provider to build it

    main.dart :

    FutureProvider<List<Map<String, dynamic>>?>(
            create: (context) {
              return RecordsDatabase.instance.getRecords();
            },
            initialData: null,
            catchError: (_, __) => <Map<String, dynamic>>[
              {'error': 'Something went wrong'}
            ],
            child: (),
          )
    

    Home

    Consumer<List<Map<String, dynamic>>?>(
            builder: (context, List<Map<String, dynamic>>? records, child) {
          if (records == null) {
            return const CircularProgressIndicator();
          } else if (records.isNotEmpty && records.first.containsKey('error')) {
            return Text(records.first['error'] as String);
          } else {
            GraphState graph = GraphState(records: records, context: context);
    
            return MultiProvider(
              providers: [
                ChangeNotifierProvider<GraphState>(create: (_) => graph),
                ChangeNotifierProvider<ButtonMode>(
                    create: (context) => ButtonMode())
              ],
              child: Scaffold(
                backgroundColor: Colors.black,
                body: Stack(children: [
                  Center(
                      child: (records.isEmpty == true)
                          ? CircularProgressIndicator()
                          : graph.records.isEmpty
                              ? Text(
                                  'No Records',
                                  style:
                                      TextStyle(color: Colors.white, fontSize: 24),
                                )
                              : MyGraph()),
    

    the GraphState model renders the spots , lines and guidelines in a big list to be rendered in a Stack in MyGraph()

    GraphState({required this.records, required this.context}) {
            titles = renderSideTitleWeights();
        spots = renderSpots();
        spotLines = renderLines();
        horizontalGuidelines = renderHorizontalLines();
        graphList = new List.from(horizontalGuidelines)
          ..addAll(spotLines)
          ..addAll(spots);
      }
    
    
    //render the spots of the graph
      //render the spots of the graph
      List<GraphSpot> renderSpots() {
       
        List<GraphSpot> spots = spotsXPos.mapIndexed<GraphSpot>((record, index) {
          return GraphSpot(
            x: record['xPos'],
            y: record['yPos'],
            date: record['record_date'],
            weight: record['weight'],
            id: index,
            selected: false,
                 );
        }).toList();
    
        return spots;
      }
    

    and the GraphSpot widget render the spots on the graph :

    class GraphSpot extends StatefulWidget {
      final double x;
      final double y;
      final String date;
      final double weight;
      final int id;
      final bool selected;
    
      GraphSpot({
        required this.x,
        required this.y,
        required this.date,
        required this.weight,
        required this.id,
        required this.selected,
      });
    
      @override
      _GraphSpotState createState() => _GraphSpotState();
    }
    
    class _GraphSpotState extends State<GraphSpot> {
      @override
      Widget build(BuildContext context) {
        return Consumer<ButtonMode>( //ButtonMode change the add button to edit and delete
          builder: (context, buttonMode, child) {
            return Positioned(
              left: widget.x - 5, //minus half of the width of the spot to center
              bottom: widget.y -
                  10, //minus half of the height of the spot and padding to center
              child: GestureDetector(
                onTap: () {
                  !widget.selected
                      ? buttonMode.setEditing()
                      : buttonMode.setAdd();
            
                },
                child: Column(
                  children: [
                    Container(
                      width: 40,
                      decoration: new BoxDecoration(
                        color: Colors.lightGreen,
                        shape: BoxShape.rectangle,
                      ),
                      child: Text(widget.weight.toStringAsFixed(1),
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.blue,
                              fontSize: 14,
                              fontWeight: FontWeight.bold)),
                    ),
                    DecoratedBox(
                      decoration: selected
                          ? BoxDecoration(
                              shape: BoxShape.circle,
                              border: Border.all(width: 3, color: Colors.red))
                          : BoxDecoration(shape: BoxShape.circle),
                      child: Padding(
                        padding: const EdgeInsets.all(5.0),
                        child: Container(
                          width: 10,
                          height: 10,
                          decoration: BoxDecoration(
                            color: Colors.blue,
                            shape: BoxShape.circle,
                          ),
                        ),
                      ),
                    )
                  ],
                ),
              ),
            );
          },
        );
      }
    }
    

    I have no idea where in my code and how I can implement this .