我正在尝试使用Flutter实现自定义导航抽屉。我想将注销选项附加到抽屉底部。问题是退出选项上方的元素数未知(从3到17)。
因此,如果这些小部件占据了抽屉一半的空间,则注销选项将位于底部,如果它们过多,则您必须滚动查看所有部件,然后注销选项将简直是最后一个。
我还试图为前两个选项提供绿色背景色。您会推荐我哪一个小部件树?我想到了ListView小部件,它将小部件列表作为构造函数中的参数。
因此,我可以为前两个项目解决不同的背景色。但是我仍然不知道如何将注销选项附加到底部。在这种情况下,它位于抽屉的底部,但有可能发生,其他选项将大于屏幕尺寸,在这种情况下,应将其放置在整个列表的底部。
编辑:我已经为问题添加了设计。注销选项是称为Odhlášení的选项。在这种情况下,它位于抽屉的底部,但有可能发生,其他选项将大于屏幕尺寸,在这种情况下,应将其放置在整个列表的底部。
答案 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
的结尾,您需要做两件事:
更新2-间隔的LogOutButton直到大列表:
实现所描述的行为是一个更困难的步骤。您必须检查ListView
是否超出屏幕并且可以滚动。
为此,我编写了以下简短代码段:
bool isListLarge() {
return controller.positions.isNotEmpty && physics.shouldAcceptUserOffset(controller.position);
}
如果ListView
超出其限制,它将返回true。现在,我们可以根据isListViewLarge
的结果刷新视图的状态。下面再次是完整的代码示例。
独立代码示例(更新2:间隔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> {
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: () => {})
],
),
);
}
}