将ListView的最后一个元素修复到屏幕底部

问题描述 投票:1回答:1

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

因此,如果这些小部件占用抽屉的一半空间,那么注销选项将位于底部,如果它们太多并且您必须滚动以查看它们全部,那么注销选项将只是持续。

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

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

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

设计:Design example

flutter navigation-drawer flutter-layout
1个回答
2
投票

您只需使用ListView来管理“17”导航选项。将这个ListView包裹在Column中。 ListView将是第二个孩子的Column的第一个孩子,因此放在底部,将是你的退出行动。

如果您在ListTile中使用透明小部件(如ListView)来显示导航选项,您可以将其简单地包装在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:Spaced LogOutButton直到大型List):

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);
  }
}

独立代码示例(Update 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: () => {})
        ],
      ),
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.