Пользовательский нижний лист Flutter

У меня есть ListView, где я хочу реализовать хороший способ удаления элементов списка, используя нижний лист с включенными действиями. Первоначально я пошел по пути простого вызова showBottomSheet() в onLongPress обработчике событий для элементов моего списка, который успешно открывал бы нижний лист с включенными моими кнопками действий. Однако это автоматически добавит кнопку возврата к AppBar, чего я не хочу.

Затем я пошел по пути опробования анимаций, таких как SlideTransition и AnimatedPositioned:

class FoldersListWidget extends StatefulWidget {
  @override
  _FoldersListWidgetState createState() => _FoldersListWidgetState();
}

class _FoldersListWidgetState extends State<FoldersListWidget>
    with SingleTickerProviderStateMixin {
  double _bottomPosition = -70;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        FutureBuilder<List<FolderModel>>(
          future: Provider.of<FoldersProvider>(context).getFolders(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) {
              return Center(
                child: CircularProgressIndicator(),
              );
            }
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (context, i) {
                final folder = snapshot.data[i];
                return Card(
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(15),
                  ),
                  margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
                  elevation: 1,
                  child: ListTile(
                    title: Text(folder.folderName),
                    leading: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Container(
                          width: 50,
                          child: Consumer<FoldersProvider>(
                            builder:
                                (BuildContext context, value, Widget child) {
                              return value.deleteFolderMode
                                  ? CircularCheckBox(
                                      value: false,
                                      onChanged: (value) {},
                                    )
                                  : Icon(
                                      Icons.folder,
                                      color: Theme.of(context).accentColor,
                                    );
                            },
                          ),
                        ),
                      ],
                    ),
                    subtitle: folder.numberOfLists != 1
                        ? Text('${folder.numberOfLists} items')
                        : Text('${folder.numberOfLists} item'),
                    onTap: () {},
                    onLongPress: () {
                      Provider.of<FoldersProvider>(context, listen: false)
                          .toggleDeleteFolderMode(true); // removes fab from screen
                      setState(() {
                        _bottomPosition = 0;
                      });
                    },
                  ),
                );
              },
            );
          },
        ),
        AnimatedPositioned(
          bottom: _bottomPosition,
          duration: Duration(milliseconds: 100),
          child: ClipRRect(
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(25),
              topRight: Radius.circular(25),
            ),
            child: Container(
              height: 70,
              width: MediaQuery.of(context).size.width,
              color: Theme.of(context).colorScheme.surface,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  Expanded(
                    child: IconAboveTextButton(
                      icon: Icon(Icons.cancel),
                      text: 'Cancel',
                      textColour: Colors.black,
                      opacity: 0.65,
                      onTap: () => setState(() {
                        _bottomPosition = -70;
                      }),
                    ),
                  ),
                  VerticalDivider(
                    color: Colors.black26,
                  ),
                  Expanded(
                    child: IconAboveTextButton(
                      icon: Icon(Icons.delete),
                      text: 'Delete',
                      textColour: Colors.black,
                      opacity: 0.65,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
}

При этом нижняя часть Container включается и выключается, но моя проблема в том, что она охватывает последний элемент списка:

Может ли кто-нибудь предложить лучший способ сделать это или просто способ отрегулировать высоту ListView так, чтобы, когда Container сдвигается вверх, ListView также сдвигается вверх.


person rejy11    schedule 10.02.2020    source источник


Ответы (1)


Оберните ListView.builder внутри контейнера и установите его нижнее заполнение как (70 + 16) 70 (высота нижнего листа), 16 (некоторые отступы по умолчанию, чтобы он выглядел лучше, если хотите).

return Container(
padding: EdgetInset.ony(bottom: (70+16)),
         child:ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (context, i) {
               .....
               .....
person Dev    schedule 10.02.2020
comment
и оживить значение, которое я предоставляю для bottom от 0 до 70 в зависимости от того, отображается ли нижний контейнер на экране? - person rejy11; 10.02.2020
comment
ты можешь padding: EdgetInset.ony(bottom: (-(_bottomPosition )+16)) - person Dev; 10.02.2020
comment
Я использовал AnimatedContainer, который предоставляет свойство duration, похоже, это сработало, спасибо :) - person rejy11; 10.02.2020