将ListView的最后一个元素固定到屏幕底部

时间:2019-03-28 07:46:58

标签: flutter navigation-drawer flutter-layout

我正在尝试使用Flutter实现自定义导航抽屉。我想将注销选项附加到抽屉底部。问题是退出选项上方的元素数未知(从3到17)。

因此,如果这些小部件占据了抽屉一半的空间,则注销选项将位于底部,如果它们过多,则您必须滚动查看所有部件,然后注销选项将简直是最后一个。

我还试图为前两个选项提供绿色背景色。您会推荐我哪一个小部件树?我想到了ListView小部件,它将小部件列表作为构造函数中的参数。

因此,我可以为前两个项目解决不同的背景色。但是我仍然不知道如何将注销选项附加到底部。在这种情况下,它位于抽屉的底部,但有可能发生,其他选项将大于屏幕尺寸,在这种情况下,应将其放置在整个列表的底部。

编辑:我已经为问题添加了设计。注销选项是称为Odhlášení的选项。在这种情况下,它位于抽屉的底部,但有可能发生,其他选项将大于屏幕尺寸,在这种情况下,应将其放置在整个列表的底部。

设计: Design example

1 个答案:

答案 0 :(得分:0)

您只需使用ListView来管理“ 17”导航选项。将此ListView包裹在Column中。 ListView将是Column的第一个孩子,因此,第二个孩子位于您的注销操作的最下面。

如果您在ListView内部使用透明的小部件(例如ListTile)来显示导航选项,则只需将其包装在Container中。 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. Expanded替换为Flexible
  2. shrinkWrap: true内设置ListView

更新2-间隔的LogOutButton直到大列表: 实现所描述的行为是一个更困难的步骤。您必须检查ListView是否超出屏幕并且可以滚动。

为此,我编写了以下简短代码段:

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

如果ListView超出其限制,它将返回true。现在,我们可以根据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: () => {})
        ],
      ),
    );
  }
}