我正在尝试使用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直到大型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);
}
}
独立代码示例(Update 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: () => {})
],
),
);
}
}