Закрепить последний элемент ListView в нижней части экрана - PullRequest
2 голосов
/ 28 марта 2019

Я пытаюсь создать пользовательский навигационный ящик с помощью Flutter. Я хотел бы прикрепить опцию выхода из системы в нижней части ящика. Проблема в том, что количество элементов над параметром выхода из системы неизвестно (от 3 до 17).

Так что, если эти виджеты занимают половину пространства ящика, тогда опция выхода из системы будет внизу, а если их слишком много и вам нужно прокрутить, чтобы увидеть их все, тогда опция выхода из системы будет будь просто последним.

Я также пытаюсь дать первым двум вариантам зеленый цвет фона. Какое дерево виджетов вы бы мне порекомендовали? Я думал о виджете ListView , он принимает список виджетов в качестве аргумента в конструкторе.

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

РЕДАКТИРОВАТЬ: я добавил дизайн к вопросу. Опция выхода из системы называется Odhlášení. В этом случае он находится внизу ящика, но может случиться, что другие параметры будут больше, чем размер экрана, и в этом случае его следует поместить внизу всего списка.

Дизайн: Design example

1 Ответ

2 голосов
/ 28 марта 2019

Вы можете просто использовать ListView для управления 17 вариантами навигации. Оберните это ListView внутри столбца . ListView будет первым потомком Column второго потомка, поэтому размещение внизу будет вашим выходом из системы.

Если вы используете прозрачные виджеты (например, ListTile ) внутри ListView для отображения параметров навигации, вы можете просто обернуть их внутри Контейнера . Container, помимо многих других виджетов, позволяет вам установить новый цвет фона с его атрибутом color.

При таком подходе дерево виджетов будет выглядеть следующим образом:

- Column                 // Column to place your LogutButton always below the ListView
  - ListView             // ListView to wrap all your navigation scrollable
    - Container          // Container for setting the color to green
      - GreenNavigation
    - Container
      - GreenNavigation
    - Navigation
    - Navigation
    - ...
  - LogOutButton

Обновление 1 - Sticky LogOutButton: Для достижения LogOutButton прилипания к концу ListView вам необходимо сделать две вещи:

  1. Заменить Расширенный на Гибкий
  2. Набор shrinkWrap: true внутри ListView

Обновление 2 - интервал LogOutButton до большого списка: Достижение описанного поведения - более сложный шаг. Вам нужно проверить, превышает ли ListView экран и можно ли его прокручивать.

Для этого я написал короткий фрагмент:

  bool isListLarge() {
    return controller.positions.isNotEmpty && physics.shouldAcceptUserOffset(controller.position);
  }

Он вернет true, если ListView превысит свои ограничения. Теперь мы можем обновить состояние просмотра в зависимости от результата isListViewLarge. Ниже снова полный пример кода.


Пример автономного кода ( Обновление 2: интервал LogOutButton до большого списка ):

Demo Update 2

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        drawer: MyDrawer(),
      ),
    );
  }
}

class MyDrawer extends StatefulWidget {
  @override
  _MyDrawerState createState() => _MyDrawerState();
}

class _MyDrawerState extends State<MyDrawer> {
  ScrollController controller = ScrollController();
  ScrollPhysics physics = ScrollPhysics();

  int entries = 4;

  @override
  Widget build(BuildContext context) {
    Widget logout = IconButton(
        icon: Icon(Icons.exit_to_app),
        onPressed: () => {setState(() => entries += 4)});

    List<Widget> navigationEntries = List<int>.generate(entries, (i) => i)
        .map<Widget>((i) => ListTile(
              title: Text(i.toString()),
            ))
        .toList();

    if (this.isListLarge()) {  // if the List is large, add the logout to the scrollable list
      navigationEntries.add(logout);
    }

    return Drawer(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,  // place the logout at the end of the drawer
        children: <Widget>[
          Flexible(
            child: ListView(
              controller: controller,
              physics: physics,
              shrinkWrap: true,
              children: navigationEntries,
            ),
          ),
          this.isListLarge() ? Container() : logout // if the List is small, add the logout at the end of the drawer
        ],
      ),
    );
  }

  bool isListLarge() {
    return controller.positions.isNotEmpty && physics.shouldAcceptUserOffset(controller.position);
  }
}

Пример автономного кода ( Обновление 1: Sticky LogOutButton ):

Demo Updated

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        drawer: MyDrawer(),
      ),
    );
  }
}

class MyDrawer extends StatefulWidget {
  @override
  _MyDrawerState createState() => _MyDrawerState();
}

class _MyDrawerState extends State<MyDrawer> {
  int entries = 4;

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: Column(
        children: <Widget>[
          Flexible(
            child: ListView(
              shrinkWrap: true,
              children: List<int>.generate(entries, (i) => i)
                  .map((i) => ListTile(
                        title: Text(i.toString()),
                      ))
                  .toList(),
            ),
          ),
          IconButton(
              icon: Icon(Icons.exit_to_app),
              onPressed: () => {setState(() => entries += 4)})
        ],
      ),
    );
  }
}

Пример автономного кода ( Старый: прилипание к низу ):

Demo

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        drawer: MyDrawer(),
      ),
    );
  }
}

class MyDrawer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: Column(
        children: <Widget>[
          Expanded(
            child: ListView(
              children: List<int>.generate(40, (i) => i + 1)
                  .map((i) => ListTile(
                        title: Text(i.toString()),
                      ))
                  .toList(),
            ),
          ),
          IconButton(icon: Icon(Icons.exit_to_app), onPressed: () => {})
        ],
      ),
    );
  }
}
...