是否可以检测抽屉何时打开,以便我们可以运行一些例程来更新其内容?
我的一个典型用例是显示关注者的数量,喜欢...为此,我需要轮询服务器以获取此信息,然后显示它。
我尝试实现NavigatorObserver来捕捉Drawer可见/隐藏的时刻,但NavigatorObserver没有检测到任何关于Drawer的内容。
以下是链接到NavigatorObserver的代码:
import 'package:flutter/material.dart';
typedef void OnObservation(Route<dynamic> route, Route<dynamic> previousRoute);
typedef void OnStartGesture();
class NavigationObserver extends NavigatorObserver {
OnObservation onPushed;
OnObservation onPopped;
OnObservation onRemoved;
OnObservation onReplaced;
OnStartGesture onStartGesture;
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
if (onPushed != null) {
onPushed(route, previousRoute);
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
if (onPopped != null) {
onPopped(route, previousRoute);
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
if (onRemoved != null)
onRemoved(route, previousRoute);
}
@override
void didReplace({ Route<dynamic> oldRoute, Route<dynamic> newRoute }) {
if (onReplaced != null)
onReplaced(newRoute, oldRoute);
}
@override
void didStartUserGesture() {
if (onStartGesture != null){
onStartGesture();
}
}
}
和这个观察者的初始化
void main(){
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
final NavigationObserver _observer = new NavigationObserver()
..onPushed = (Route<dynamic> route, Route<dynamic> previousRoute) {
print('** pushed route: $route');
}
..onPopped = (Route<dynamic> route, Route<dynamic> previousRoute) {
print('** poped route: $route');
}
..onReplaced = (Route<dynamic> route, Route<dynamic> previousRoute) {
print('** replaced route: $route');
}
..onStartGesture = () {
print('** on start gesture');
};
@override
void initState(){
super.initState();
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Title',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SplashScreen(),
routes: <String, WidgetBuilder> {
'/splashscreen': (BuildContext context) => new SplashScreen(),
},
navigatorObservers: <NavigationObserver>[_observer],
);
}
}
感谢您的帮助。
答案 0 :(得分:4)
我认为一个简单的解决方案是覆盖leading
的{{1}}属性,这样您就可以在按下菜单图标时根据该操作调用API。
然而,我可能误解了您的问题,因为根据您提供的用例,您通常需要以一种可以监听的方式管理它,以便自动更新值,这样我就可以了不知道抽屉打开时你想要触发什么。
无论如何,这是一个例子。
AppBar
答案 1 :(得分:3)
这对我有用。
通过任何操作打开抽屉时运行initState。
通过任何动作关闭抽屉时运行。
希望它能对您有所帮助。
class MyDrawer extends StatefulWidget {
@override
_MyDrawerState createState() => _MyDrawerState();
}
class _MyDrawerState extends State<MyDrawer> {
@override
void initState() {
super.initState();
print("open");
}
@override
void dispose() {
print("close");
super.dispose();
}
@override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
Text("test1"),
Text("test2"),
Text("test3"),
],
),
);
}
}
答案 2 :(得分:3)
不幸的是,目前没有readymade solution。
您可以为此使用肮脏的技巧:观察抽屉的可见位置。
例如,我使用这种方法来同步按钮上图标的动画和“抽屉”框的位置。
解决此问题的代码,您可以在下面看到:
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class DrawerListener extends StatefulWidget {
final Widget child;
final ValueChanged<FractionalOffset> onPositionChange;
DrawerListener({
@required this.child,
this.onPositionChange,
});
@override
_DrawerListenerState createState() => _DrawerListenerState();
}
class _DrawerListenerState extends State<DrawerListener> {
GlobalKey _drawerKey = GlobalKey();
int taskID;
Offset currentOffset;
@override
void initState() {
super.initState();
_postTask();
}
_postTask() {
taskID = SchedulerBinding.instance.scheduleFrameCallback((_) {
if (widget.onPositionChange != null) {
final RenderBox box = _drawerKey.currentContext?.findRenderObject();
if (box != null) {
Offset newOffset = box.globalToLocal(Offset.zero);
if (newOffset != currentOffset) {
currentOffset = newOffset;
widget.onPositionChange(
FractionalOffset.fromOffsetAndRect(
currentOffset,
Rect.fromLTRB(0, 0, box.size.width, box.size.height),
),
);
}
}
}
_postTask();
});
}
@override
void dispose() {
SchedulerBinding.instance.cancelFrameCallbackWithId(taskID);
if (widget.onPositionChange != null) {
widget.onPositionChange(FractionalOffset(1.0, 0));
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
key: _drawerKey,
child: widget.child,
);
}
}
如果您只对打开或关闭框的最终事件感兴趣,那么只需在initState
和dispose
函数中调用回调即可。
答案 3 :(得分:3)
由于 https://github.com/flutter/flutter/pull/67249 已经与 Flutter 2.0 合并并发布,这里是检测抽屉打开/关闭的正确方法:
Scaffold(
onDrawerChanged: (isOpened) {
//todo what you need for left drawer
},
onEndDrawerChanged: (isOpened) {
//todo what you need for right drawer
},
)
答案 4 :(得分:0)
最佳解决方案
ScaffoldState
有一个有用的方法isDrawerOpen
,它提供了打开/关闭状态。
示例
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(context) {
return WillPopScope(
child: Scaffold(
key: _scaffoldKey,
drawer: SideNavigation(),
onWillPop: () async {
// drawer is open do things accordingly
if (_scaffoldKey.currentState.isDrawerOpen) {
Navigator.of(context).pop();
return false;
}
return true;
});}
答案 5 :(得分:0)
当这个问题被发布时,完成这个问题有点技巧。但是从 Flutter 2.0 开始,这很容易。在您的 Scaffold 中,您可以按如下方式检测右侧抽屉和左侧抽屉。
@override
Widget build(BuildContext context) {
return Scaffold(
onDrawerChanged: (isOpened) {
*//Left drawer, Your code here,*
},
onEndDrawerChanged: (isOpened) {
*//Right drawer, Your code here,*
},
);
}
答案 6 :(得分:0)
您可以简单地使用 onDrawerChanged 来检测抽屉是在 Scaffold 小部件中打开还是关闭。
财产:
{void 函数(布尔)? onDrawerChanged}
类型:void Function(bool)?
Scaffold.drawer 打开或关闭时调用的可选回调。
示例:
@override 小部件构建(BuildContext 上下文){
return Scaffold(
onDrawerChanged:(val){
if(val){
setState(() {
//foo bar;
});
}else{
setState(() {
//foo bar;
});
}
},
drawer: Drawer(
child: Container(
)
));
}
答案 7 :(得分:-1)
ScaffoldState 中有 isDrawerOpen 属性,所以你可以随时查看。
创建全局密钥;
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
将其分配给脚手架
Scaffold(
key: scaffoldKey,
appBar: ..)
检查应用程序中的任何位置
bool opened =scaffoldKey.currentState.isDrawerOpen;