Одиночный выбор ListTile (Flutter)

#flutter #dart

#флаттер #dart

Вопрос:

Конечно, это простое решение для этого, но я не могу понять это — я совсем новичок в flutter — still. В чем проблема?

У меня есть диалоговое окно с 4 листами списка, которые должны работать как селекторы для радиуса gps, однако у меня проблема с одним выбором. Теперь, когда выбран один — все выбираются одновременно. Итак, мне нужно найти способ, как сделать одиночный выбор для каждого из них (если один выбран, остальные должны быть невыбраны), а затем передать его значение, например. 10, 25 и т.д. при нажатии кнопки «Выбрать».

 class RadiusSelectorDialog extends StatefulWidget {
  RadiusSelectorDialog({Key key}) : super(key: key);

  @override
  _RadiusSelectorDialogState createState() => _RadiusSelectorDialogState();
}

class _RadiusSelectorDialogState extends State<RadiusSelectorDialog>
    with TitleDescriptionTextMixin {
  bool selected = false;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      scrollable: true,
      contentPadding: EdgeInsets.all(4.0),
      title: Center(child: smallerBoldText('Select radius:', fontSize: 15.0)),
      content: Column(
        children: [
          Divider(
            color: Colors.grey,
            height: 2.0,
          ),
          CustomListTile(
            label: '10 km',
            selected: selected,
            onSelect: () => _onSelect(selected),
          ),
          CustomListTile(
            label: '25 km',
            selected: selected,
            onSelect: () => _onSelect(selected),
          ),
          CustomListTile(
            label: '50 km',
            selected: selected,
            onSelect: () => _onSelect(selected),
          ),
          CustomListTile(
            label: '75 km',
            selected: selected,
            onSelect: () => _onSelect(selected),
          ),
        ],
      ),
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(16.0))),
      actions: [
        FlatButton(
            child: Text('Select',
                style: TextStyle(
                    color: LegionColors.primaryRedHigh,
                    fontWeight: FontWeight.bold)),
            onPressed: () {
              Navigator.pop(context);
            })
      ],
    );
  }

  void _onSelect(bool value) {
    setState(() {
      if (selected == false) {
        selected = true;
      } else {
        selected = false;
      }
    });
  }
}

 

Мой пользовательский список для выбора.

 
class CustomListTile extends StatelessWidget {
  final String label;
  final bool selected;
  final Function onSelect;

  const CustomListTile(
      {Key key,
      @required this.selected,
      @required this.onSelect,
      @required this.label})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListTile(
          title: Center(
              child: Text(label,
                  style: selected == false
                      ? TextStyle(color: Colors.black)
                      : TextStyle(
                          color: LegionColors.primaryRedHigh,
                          fontWeight: FontWeight.bold,
                        ))),
          selected: selected,
          onTap: onSelect,
          shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(16.0))),
        ),
        Divider(
          color: Colors.grey,
          height: 2.0,
        ),
      ],
    );
  }
}


 

Ответ №1:

Вы используете одну и ту же переменную selected , чтобы определить, выбран ли элемент для всех элементов. Вот что происходит,

  1. Задействован один элемент
  2. setState -> selected -> true
  3. Все элементы обновляются, чтобы быть selected

Чтобы избежать этого

  1. вы можете переместить идентификатор внутри CustomListTile и сделать его StatefulWidget.
  2. Или, если вам нужно поддерживать статус выбора в родительском элементе, вы можете использовать Map реализацию
   HashMap<String, bool> selectedState = new HashMap();

  void updateSelectionStatus(String selectedTileId, bool status) {
    setState(() {
      selectedState[selectedTileId] = status;
    });
  }
 

И тогда вы можете использовать его следующим образом

 CustomListTile(
            label: '75 km',
            selected: selectedState['your-unique-id'],
            onSelect: () => updateSelectionStatus('your-unique-id', !selectedState['your-unique-id']),
          )
 

Комментарии:

1. Devayan Sarkar — кажется, это хорошее решение (с map), однако теперь оно показывает, что выбранное значение равно нулю — я даже меняю свойство customtile на значение «flase» по умолчанию, но selectedState каким-то образом очищает его и передает ему значение null.

2. Вы заполнили selectedState ? dart @override void initState() { super.initState(); setState(() { selectedState['tile1'] = false; selectedState['tile2'] = false; selectedState['tile3'] = false; selectedState['tile4'] = false; }); }

3. Теперь это почти префект 🙂 Мне нужно заблокировать другие плитки для выбора. Чтобы сделать его единым списком выбора. Я думаю о инструкции switch.

4. Если вы пытаетесь выбрать только один из них. Тогда я бы предложил альтернативный подход. dart int selectedItem = 0 ; void updateSelectedItem(int index){ setState(() { _selectedIndex = index; }); } // Use it like this CustomListTile( label: '75 km', selected: 1 == selectedItem, onSelect: () => updateSelectedItem(1), ) CustomListTile( label: '85 km', selected: 2 == selectedItem, onSelect: () => updateSelectedItem(2), )

Ответ №2:

Проверьте его рабочий код на официальном веб-сайте Flutter https://api.flutter.dev/flutter/material/ListTile/selected.html