flutter - 将 ListView 的最后一个元素固定到屏幕底部
问题描述
我正在尝试使用 Flutter 实现自定义导航抽屉。我想在抽屉底部附加注销选项。问题是注销选项上方的元素数量是未知的(从 3 到 17)。
因此,如果这些小部件占用抽屉空间的一半,则注销选项将位于底部,如果它们太多并且您必须滚动查看它们,那么注销选项将只是最后的。
我也试图给前两个选项一个绿色的背景颜色。你会推荐我哪个小部件树?我想到了ListView小部件,它将小部件列表作为构造函数中的参数。
因此我可以解决前两项的不同背景颜色。但我仍然不知道如何将注销选项附加到底部。在这种情况下,它位于抽屉的底部,但它可能会发生,其他选项将大于屏幕尺寸,在这种情况下,它应该放在整个列表的底部。
编辑:我已经为这个问题添加了一个设计。注销选项是称为 Odhlášení 的选项。在这种情况下,它位于抽屉的底部,但它可能会发生,其他选项将大于屏幕尺寸,在这种情况下,它应该放在整个列表的底部。
解决方案
您可以简单地使用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
您需要做两件事:
更新 2 - 间隔 LogOutButton 直到大列表:
实现所描述的行为是一个更困难的步骤。您必须检查是否ListView
超出屏幕并且可滚动。
为此,我写了这个简短的片段:
bool isListLarge() {
return controller.positions.isNotEmpty && physics.shouldAcceptUserOffset(controller.position);
}
ListView
如果超出其限制,它将返回 true 。现在我们可以根据isListViewLarge
. 下面又是一个完整的代码示例。
独立代码示例(更新 2:Spaced LogOutButton until large List):
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):
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)})
],
),
);
}
}
独立代码示例(旧:坚持到底):
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: () => {})
],
),
);
}
}
推荐阅读
- php - PHP如何组合到数组值
- python - 在其他函数中重新定义python函数
- c# - 在 .NET Core API 中返回 RSS 提要
- python - 将 CSV 数据从 Google Storage 加载到 Bigquery 的 Python 代码?
- internet-explorer - IE 浏览器兼容性问题:Prime-ng Icons、Font-Awesome Icons 和 Clarity html
- java - Wildfly 上的 EJB 部署看不到休眠
- laravel - Laravel 应用程序无法在本地写入文件,使用 docker 抛出权限被拒绝
- ios - 将屏幕截图上传到 iTunes Connect
- c# - 在 C# 中,是否可以将应该由 String 的 format 方法格式化的对象作为数组传递?
- html - 是什么让最后一张照片与其他照片相比如此之大?