Radio button not changing the selection in Flutter

Issue

I am creating dynamic radio button and managed to show it. However, when I tap on it, it is not changing the selection. I can see onchanged event fired I am getting the output but I think SetState is not working as expected.

Here is the code.

class FruitsList {
  String name;
  int index;
  FruitsList({this.name, this.index});
}

int  _selectedRadioIndex = 1;

// Default Radio Button Item
  String radioItem = 'Mango';
 
  // Group Value for Radio Button.
  int id = 1;
 
  List<FruitsList> fList = [
    FruitsList(
      index: 1,
      name: "Mango",
    ),
    FruitsList(
      index: 2,
      name: "Apple",
    ),
    FruitsList(
      index: 3,
      name: "Banana",
    ),
    FruitsList(
      index: 4,
      name: "Cheery",
    ),
  ];
Column(
              children: 
                fList.map((data) => RadioListTile(
                  title: Text("${data.name}"),
                  groupValue: id,
                  value: data.index,
                  onChanged: (val) {
                    setState(() {
                      radioItem = data.name ;
                      id = data.index;
                      print(id);
                      print(radioItem);
                      print(val);
                      _selectedRadioIndex = val;
                    });
                  }, 
                )).toList(),
            ),

What am I doing wrong?

Update

As suggested by chunhugun.

I tried below code.

showDialog(
  context: context,
  builder: (context) {
      return StatefulBuilder(
      builder: (context, setState) {
  Column(
              children:            
                fList.map((data) => RadioListTile(
                  title: Text("${data.name}"),
                  groupValue: id,//_selected,//id,
                  value: data.index,
                  onChanged: (val) {
                    setState(() {
                      radioItem = data.name ;
                      id = data.index;
                      print(id);
                      print(radioItem);
                      print(val);
                      _selectedRadioIndex = val;
                    });
                  }, 
                )).toList(),
            );
  }
  );
  },
  );

But it is giving error on these places.

showDialog(
  context: context,
  builder: (context) {

'showDialog' must have a method body because '_ApointmentPriceState' isn't abstract.
Try making '_ApointmentPriceState' abstract, or adding a body to 'showDialog'.

Solution

You can copy paste run full code below
You can wrap Row with StatefulBuilder and use List<int> _selectedRadioIndexList and CardNo to control
code snippet

List<int> _selectedRadioIndexList = [];
int CardNo = -1;
...
_selectedRadioIndexList.add(0);
CardNo = CardNo + 1;
int thisCardNo = CardNo;
... 
_selectedRadioIndexList[thisCardNo] = val;  


StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            return Row(
              children: fList
                  .map((data) => Container(
                    width: 100,
                    child: RadioListTile(
                          title: Text("${data.name}"),
                          groupValue: id,
                          value: data.index,
                          onChanged: (val) {
                            setState(() {
                              radioItem = data.name;
                              id = data.index;
                              print(id);
                              print(radioItem);
                              print(val);
                              _selectedRadioIndex = val;
                            });
                          },
                        ),
                  ))
                  .toList(),
            );
          })

working demo

enter image description here

full code

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

class FruitsList {
  String name;
  int index;
  FruitsList({this.name, this.index});
}

class Price extends StatefulWidget {
  @override
  _PriceState createState() => _PriceState();
}

class _PriceState extends State<Price> {
  static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  int currentIndex = 0;
  String person;
  String age;
  String job;

  // Default Radio Button Item
  String radioItem = 'Mango';

  // Group Value for Radio Button.
  int id = 1;
  //int _selectedRadioIndex = 1;
  List<int> _selectedRadioIndexList = [];

  List<FruitsList> fList = [
    FruitsList(
      index: 1,
      name: "Mango",
    ),
    FruitsList(
      index: 2,
      name: "Banana",
    ),
    FruitsList(
      index: 3,
      name: "Apple",
    ),
    FruitsList(
      index: 4,
      name: "Cherry",
    ),
  ];
  int CardNo = -1;
  @override
  void initState() {
    super.initState();
    cards.add(createCard());
  }

  var nameTECs = <TextEditingController>[];
  var ageTECs = <TextEditingController>[];
  var jobTECs = <TextEditingController>[];

  var cards = <Card>[];

  Card createCard() {
    var nameController = TextEditingController();
    var ageController = TextEditingController();
    var jobController = TextEditingController();
    nameTECs.add(nameController);
    ageTECs.add(ageController);
    jobTECs.add(jobController);
    _selectedRadioIndexList.add(0);
    CardNo = CardNo + 1;
    int thisCardNo = CardNo;

    return Card(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text('Service ${cards.length + 1}'),
          TextFormField(
            style: TextStyle(color: Colors.blue),
            controller: nameController,
            decoration: InputDecoration(labelText: 'Name'),
            validator: validatetext,
            onSaved: (String val) {
              person = val;
            },
          ),

          TextFormField(
            style: TextStyle(color: Colors.blue),
            controller: ageController,
            decoration: InputDecoration(labelText: 'age'),
            validator: validatetext,
            onSaved: (String val) {
              age = val;
            },
          ),
          TextFormField(
            style: TextStyle(color: Colors.blue),
            controller: jobController,
            decoration: InputDecoration(labelText: 'Job'),
            validator: validatetext,
            onSaved: (String val) {
              job = val;
            },
          ),

          //Expanded(
          //            child: Container(
          //            height: 350.0,
          //            child:
          StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            return Row(
              children: fList
                  .map((data) => Container(
                        width: 100,
                        child: RadioListTile(
                          title: Text("${data.name}"),
                          groupValue: id,
                          value: data.index,
                          onChanged: (val) {
                            setState(() {
                              radioItem = data.name;
                              id = data.index;
                              print(id);
                              print(radioItem);
                              print(val);
                              _selectedRadioIndexList[thisCardNo] = val;
                            });
                          },
                        ),
                      ))
                  .toList(),
            );
          }),
          //)),

          /* CheckboxListTile(
        title: Text("title text"),
        value: checkedValue,
        onChanged: (newValue) {
                     setState(() {
                       checkedValue = newValue;
                     });
                   },
        //onChanged: (newValue) { ... },
        controlAffinity: ListTileControlAffinity.leading,  //  <-- leading Checkbox
      ), */

          SizedBox(height: 10),
        ],
      ),

      //   ),
    );
  }

  void _validateInputs() {
    print('button');
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      _onDone();
    } else {}
  }

  _onDone() {
    updateProfile();
    List<PersonEntry> entries = [];
    for (int i = 0; i < cards.length; i++) {
      var name = nameTECs[i].text;
      var age = ageTECs[i].text;
      var job = jobTECs[i].text;
      entries.add(PersonEntry(name, age, job));
    }
  }

  ///////// Save to DB ////////////////////
  Future updateProfile() async {
    try {
      for (int i = 0; i < cards.length; i++) {
        var name = nameTECs[i].text;
        var age = ageTECs[i].text;
        var job = jobTECs[i].text;

        Map<String, dynamic> body = {'name': name, 'age': age, 'job': job};

        print(body);
        nameTECs[i].clear();
        //if(rang == true){

        Response response = await Dio()
            .post("http://192.168.1.102:8080/adddetails.php", data: body);
        print(response.statusCode);
        if (response.statusCode == 404) {
          print('404');
        }
        if (response.statusCode == 200) {
          nameTECs[i].clear();
        }
      }
    } catch (e) {
      print("Exception Caught: $e");
    }
  }

  ///////////////////////////////

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      //appBar: myAppBar(),
      //endDrawer: myDrawer(),
      body: Column(
        children: <Widget>[
          Expanded(
            child: new Form(
              key: _formKey,
              child: ListView.builder(
                itemCount: cards.length,
                itemBuilder: (BuildContext context, int index) {
                  return cards[index];
                },
              ),
            ),
          ),
          Container(
            padding: EdgeInsets.symmetric(horizontal: 2.0),
            color: Colors.grey,
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                //    Container(
                Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: FloatingActionButton(
                      heroTag: "btn1",
                      child: Icon(Icons.add),
                      onPressed: () => setState(() => cards.add(createCard())),
                      backgroundColor: Colors.green,
                    )

                    /*RaisedButton(
                  child: Text('Add new'),
                  onPressed: () => setState(() => cards.add(createCard())),
                ),*/
                    ),
                Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: FloatingActionButton(
                      heroTag: "btn2",
                      child: Icon(Icons.remove),
                      onPressed: () => setState(() => cards.removeLast()),
                      backgroundColor: Colors.red,
                    )),
                Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: FloatingActionButton(
                      heroTag: "btn3",
                      child: Icon(Icons.save),
                      onPressed: _validateInputs),
                )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class PersonEntry {
  final String name;
  final String age;
  final String studyJob;

  PersonEntry(this.name, this.age, this.studyJob);
  @override
  String toString() {
    return 'Person: name= $name, age= $age, study job= $studyJob';
  }
}

Size get preferredSize => Size.fromHeight(kToolbarHeight);

String validatetext(String value) {
  if (value.length < 5)
    return 'More than 5 char is required';
  else
    return null;
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Price(),
    );
  }
}

Answered By – chunhunghan

Answer Checked By – Timothy Miller (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *