如何使用 RadioListTiles 制作可扩展的 ListView?

How make expandable ListView with RadioListTiles?

我更改了一个示例 ExpansionTile,添加了一些收音机。但它们无法正常工作。我想有不超过一个的选择。 Screenshot gif
这是我的代码:

import 'package:flutter/material.dart';

class ExpansionTileSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: const Text('ExpansionTile'),
        ),
        body: new ListView.builder(
          itemBuilder: (BuildContext context, int index) =>
          new EntryItem(data[index]),
          itemCount: data.length,
        ),
      ),
    );
  }
}

// One entry in the multilevel list displayed by this app.
class Entry {
  Entry(this.title, [this.children = const <Entry>[]]);

  final String title;
  final List<Entry> children;
}

// The entire multilevel list displayed by this app.
final List<Entry> data = <Entry>[
  new Entry(
    'Chapter A',
    <Entry>[
      new Entry(
        'Section A0',
        <Entry>[
          new Entry('Item A0.1'),
          new Entry('Item A0.2'),
          new Entry('Item A0.3'),
        ],
      ),
      new Entry('Section A1'),
      new Entry('Section A2'),
    ],
  ),
  new Entry(
    'Chapter B',
    <Entry>[
      new Entry('Section B0'),
      new Entry('Section B1'),
    ],
  ),
  new Entry(
    'Chapter C',
    <Entry>[
      new Entry('Section C0'),
      new Entry('Section C1'),
      new Entry(
        'Section C2',
        <Entry>[
          new Entry('Item C2.0'),
          new Entry('Item C2.1'),
          new Entry('Item C2.2'),
          new Entry('Item C2.3'),
        ],
      ),
    ],
  ),
];

// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class EntryItem extends StatefulWidget {
  const EntryItem(this.entry);
  final Entry entry;

  @override
  EntryItemState createState() {
    return new EntryItemState(entry);
  }
}

class EntryItemState extends State<EntryItem> {
  Entry entry;
  EntryItemState(Entry entry){
    this.entry = entry;
  }
  int radioValue = 0;

  void handleRadioValueChanged(int value) {
    setState(() {
      radioValue = value;
    });
  }

  Widget _buildTiles(Entry root) {
    if (root.children.isEmpty)
      return new ListTile(
          title: Row(
            children: <Widget>[
              new Text(root.title),
              new Radio(
                  key: new Key(root.title),
                  value: 1,
                  groupValue: radioValue,
                  onChanged: handleRadioValueChanged)
            ],
          )
      );
    return new ExpansionTile(
      key: new PageStorageKey<Entry>(root),
      title: new Text(root.title),
      children: root.children.map(_buildTiles).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return _buildTiles(widget.entry);
  }
}

void main() {
  runApp(new ExpansionTileSample());
}

请展示如何修正代码,使每个组中的值不超过一个。我找不到解决办法。感谢您的帮助!

如果您想选择选项,我将您的代码一一修改如下。

class ExpansionTileSample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: const Text('ExpansionTile'),
        ),
        body: new ListView.builder(
          itemBuilder: (BuildContext context, int index) =>
          new EntryItem(data[index]),
          itemCount: data.length,
        ),
      ),
    );
  }
}

// One entry in the multilevel list displayed by this app.
class Entry {
  Entry(this.title, [this.children = const <Entry>[]]);

  final String title;
  int radioValue = 0;
  final List<Entry> children;
}

// The entire multilevel list displayed by this app.
final List<Entry> data = <Entry>[
  new Entry(
    'Chapter A',
    <Entry>[
      new Entry(
        'Section A0',
        <Entry>[
          new Entry('Item A0.1'),
          new Entry('Item A0.2'),
          new Entry('Item A0.3'),
        ],
      ),
      new Entry('Section A1'),
      new Entry('Section A2'),
    ],
  ),
  new Entry(
    'Chapter B',
    <Entry>[
      new Entry('Section B0'),
      new Entry('Section B1'),
    ],
  ),
  new Entry(
    'Chapter C',
    <Entry>[
      new Entry('Section C0'),
      new Entry('Section C1'),
      new Entry(
        'Section C2',
        <Entry>[
          new Entry('Item C2.0'),
          new Entry('Item C2.1'),
          new Entry('Item C2.2'),
          new Entry('Item C2.3'),
        ],
      ),
    ],
  ),
];

// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class EntryItem extends StatefulWidget {
  const EntryItem(this.entry);
  final Entry entry;

  @override
  EntryItemState createState() {
    return new EntryItemState(entry);
  }
}

class EntryItemState extends State<EntryItem> {
  Entry entry;
  EntryItemState(Entry entry){
    this.entry = entry;
  }

  void handleRadioValueChanged(int value, Entry root) {
    setState(() {
      root.radioValue = value;
    });
  }

  Widget _buildTiles(Entry root) {
    if (root.children.isEmpty) {
      print("title: ${root.title} , radioValue: ${root.radioValue}");
      return new ListTile(
          title: Row(
            children: <Widget>[
              new Text(root.title),
              new Radio(
                  key: new Key(root.title),
                  value: 1,
                  groupValue: root.radioValue,
                  onChanged: (value) => handleRadioValueChanged(value, root))
            ],
          )
      );
    }
    return new ExpansionTile(
      key: new PageStorageKey<Entry>(root),
      title: new Text(root.title),
      children: root.children.map(_buildTiles).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return _buildTiles(widget.entry);
  }
}

我所做的更改是为每个条目分配不同的 radioValue 并仅更新 Entry 中的相关 radioValue

ADDITIONAL INFORMATION

如果您希望只能选择一个选项,那么您应该创建单选按钮的子项。您可以检查以下方法。

Widget buildRadio() {
    return new Align(
      alignment: const Alignment(0.0, -0.2),
      child: new Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          new Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              new Radio<int>(
                value: 0,
                groupValue: radioValue,
                onChanged: handleRadioValueChanged
              ),
              new Radio<int>(
                value: 1,
                groupValue: radioValue,
                onChanged: handleRadioValueChanged
              ),
              new Radio<int>(
                value: 2,
                groupValue: radioValue,
                onChanged: handleRadioValueChanged
              )
            ]
          ),
          // Disabled radio buttons
          new Row(
            mainAxisSize: MainAxisSize.min,
            children: const <Widget>[
              const Radio<int>(
                value: 0,
                groupValue: 0,
                onChanged: null
              ),
              const Radio<int>(
                value: 1,
                groupValue: 0,
                onChanged: null
              ),
              const Radio<int>(
                value: 2,
                groupValue: 0,
                onChanged: null
              )
            ]
          )
        ]
      )
    );   }