Выбор элемента в списке

Последнее обновление: 19.02.2021

По умолчанию ListView не поддерживает отслеживание выделенного элемента, и в такой ситуации нам надо создавать самим всю инфраструктуру обработки выделения элемента. В этом случае мы можем воспользоваться ранее рассмотренным виджетом GestureDetector, который позволяет отслеживать нажатия.

Например, определим следующий код:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
      home:  Scaffold(
        body: UsersList(),
        appBar: AppBar(title: Text("METANIT.COM")),)
  ));
}

class UsersList extends StatefulWidget {
  @override
  _UsersListState createState() => _UsersListState();
}
class _UsersListState extends State<UsersList> {
  final List<String> users = ["Tom", "Alice", "Sam", "Bob", "Kate"];
  int selectedIndex = -1;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
        children: [
        Text(
            selectedIndex==-1?"Не выбрано": "Выбрано: ${users[selectedIndex]}",
            style: TextStyle(fontSize: 30)),
        Expanded(child: ListView.builder(
          itemCount: users.length,
          itemBuilder: _createListView,
        ))
      ]);
  }

  Widget _createListView(BuildContext context, int index) {
    return GestureDetector(
      onTap: () {
        setState(() {
          // устанавливаем индекс выделенного элемента
          selectedIndex = index;
        });
      },
      child: Container(
        margin: EdgeInsets.symmetric(vertical: 4),
        padding: EdgeInsets.symmetric(vertical: 8),
        color: index == selectedIndex ? Colors.black12: Colors.white60,
        child: Text(users[index], style: TextStyle(fontSize: 24)),
      ),
    );
  }
}

Итак, в данном случае определен новый виджет - UsersList, который может хранить состояние. Все его состояние инкапсулировано в рамках класса _UsersListState

_UsersListState хранит список users - собственно данные, которые будут выводиться в ListView:

final List<String> users = ["Tom", "Alice", "Sam", "Bob", "Kate"];

Для отслеживания выделенного элемента нам потребуется его индекс. И для хранения индекса выделенного элемента из списка users определим отдельную переменную:

int selectedIndex = -1;

По умолчанию она равна -1, что будет выступать в качестве индикатора, что ни одного элемента еще не выбрано. После выделения элемента в ListView эта переменная будет хранить индекс выделенного элемента.

Организационно все виджеты будут помещаться в контейнер Column, в котором первый виджет - Text будет выводить значение выделенного элемента (если такой имеется):

Text(
  selectedIndex==-1?"Не выбрано": "Выбрано: ${users[selectedIndex]}",
  style: TextStyle(fontSize: 30)),

Чтобы у ListView не было проблем с заполнением пространства контейнера помещаем этот виджет в контейнер Expander. А само наполнение ListView для наглядности вынесено в отдельный метод _createListView. напомню, что в конструкторе ListView параметр itemBuilder принимает функцию, которая в качестве второго параметра получает индекс элемента:

Widget _createListView(BuildContext context, int index) {

Так из параметра метода _createListView мы можем получить индекс текущего элемента и что-то с ним сделать.

Контейнером верхнего уровня для элемента в ListView служит виджет GestureDetector, который позволяет обрабатывать нажатия.

При нажатии будет срабатывать функция, которая передается через параметр onTap виджета GestureDetector:

onTap: () {
        setState(() {
          // устанавливаем индекс выделенного элемента
          selectedIndex = index;
        });
      },

Здесь мы изменяем состояние виджета, передавая в переменную selectedIndex индекс нажатого элемента.

Сам GestureDetector содержит виджет Container, а тот - виджет Text, который выводит строку из списка users.

Чтобы выделить отмеченный элемент, в виджете Container фоновый цвет устанавливается в зависимости от того, является ли текущий индекс индексом выделенного элемента:

color: index == selectedIndex ? Colors.black12: Colors.white60,

В итоге мы сможем выделять элементы в ListView и получать их:

Выделение элементов в списке ListView в Flutter
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850