Flutter 颤振:抽屉打开时是否可以检测到?
是否可以检测抽屉何时打开,以便我们可以运行一些例程来更新其内容 我的一个典型用例是显示追随者、喜欢者的数量。。。为此,我需要轮询服务器以获取此信息,然后显示它 我尝试实现一个NavigatorObserver来捕捉抽屉被显示/隐藏的时刻,但是NavigatorObserver没有检测到抽屉的任何信息 以下是链接到NavigatorObserver的代码:Flutter 颤振:抽屉打开时是否可以检测到?,flutter,Flutter,是否可以检测抽屉何时打开,以便我们可以运行一些例程来更新其内容 我的一个典型用例是显示追随者、喜欢者的数量。。。为此,我需要轮询服务器以获取此信息,然后显示它 我尝试实现一个NavigatorObserver来捕捉抽屉被显示/隐藏的时刻,但是NavigatorObserver没有检测到抽屉的任何信息 以下是链接到NavigatorObserver的代码: import 'package:flutter/material.dart'; typedef void OnObservation(Rou
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();
}
}
}
导入“包装:颤振/材料.省道”;
类型def void OnObservation(路线路线、前一条路线);
typedef void onStart();
类NavigationObserver扩展了NavigatorObserver{
非观察性;非观察性;
一次观察一次;
未观察未移除;
无观察无替代;
开始姿势开始姿势;
@凌驾
void didPush(路由、路由前一路由){
如果(onpush!=null){
onpush(路由、先前路由);
}
}
@凌驾
void didPop(路由、路由前一路由){
if(onPopped!=null){
onPopped(路线、先前路线);
}
}
@凌驾
void didrove(路由路由,路由前一路由){
if(onRemoved!=null)
onRemoved(路线,以前的路线);
}
@凌驾
void didReplace({Route oldprote,Route newRoute}){
如果(onReplaced!=null)
onReplaced(新路线、旧路线);
}
@凌驾
void didStartUserGesture(){
if(onStart手势!=null){
onStart手势();
}
}
}
以及这个观察器的初始化
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],
);
}
}
void main(){
runApp(新的MyApp());
}
类MyApp扩展了StatefulWidget{
@凌驾
_MyAppState createState()=>new_MyAppState();
}
类MyAppState扩展了状态{
final NavigationObserver_observer=新的NavigationObserver()
..onpush=(路由路由,路由前一个路由){
打印(“**推送路线:$route”);
}
..onPopped=(路由路由,路由前一路由){
打印(“**poped route:$route”);
}
..onReplaced=(路线路线,路线前一条路线){
打印(“**替换路线:$route”);
}
…onStart手势=(){
打印(“**开始手势”);
};
@凌驾
void initState(){
super.initState();
}
//此小部件是应用程序的根。
@凌驾
小部件构建(构建上下文){
返回新材料PP(
标题:“标题”,
主题:新主题数据(
主样本:颜色。蓝色,
),
主页:新的SplashScreen(),
路线:{
“/splashscreen”:(BuildContext上下文)=>newsplashscreen(),
},
导航观察者:[\u观察者],
);
}
}
谢谢您的帮助。我认为一个简单的解决方案是覆盖
AppBar
的前导
属性,这样您就可以在按下菜单图标时访问,并基于此运行API调用
然而,我可能误解了您的问题,因为对于您提供的用例,您通常需要以一种方式来管理它,您可以听到任何将自动更新值的更改,因此我不确定在抽屉打开时您试图触发什么
无论如何,这里是一个例子
类DrawerExample扩展StatefulWidget{
@凌驾
_DroperExamplestate createState()=>新的_DroperExamplestate();
}
类_DrawerExampleState扩展状态{
GlobalKey _key=new GlobalKey();
int _计数器=0;
_handleDrawer(){
_key.currentState.openDrawer();
设置状态(){
///执行API调用
_计数器++;
});
}
@凌驾
小部件构建(构建上下文){
归还新脚手架(
键:_键,
appBar:新的appBar(
标题:新文本(“抽屉示例”),
标题:对,
前导:新图标按钮(图标:新图标(
图标菜单
),按下按钮:_handleDrawer,),
),
抽屉:新抽屉(
孩子:新中心(
子项:新文本(_counter.toString(),样式:Theme.of(context.textTheme.display1,),
),
),
);
}
}
抽屉打开/关闭时的检测和运行功能
- 通过任何操作打开抽屉时,运行
initState()
- 通过任何操作关闭抽屉时,运行
dispose()
SchedulerBinding.instance.addPostFrameCallback((_) {
// add your code here.
});
选项1的完整示例
WidgetsBinding.instance.addPostFrameCallback((_){
// Add Your Code here.
});
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// Your Code Here
});
}
不幸的是,目前没有 你可以使用肮脏的黑客:观察抽屉的可见位置 例如,我使用这种方法来同步按钮上图标的动画和抽屉盒的位置 解决此问题的代码如下所示:
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,
);
}
}
导入“包装:颤振/材料.省道”;
导入“package:flatter/scheduler.dart”;
类DroperListener扩展StatefulWidget{
最后一个孩子;
最终价值随位置变化而变化;
付款人({
@需要这个孩子,
这是一种改变,
});
@凌驾
_DroperListenerState createState()=>\u DroperListenerState();
}
类_DrawerListenerState扩展状态{
GlobalKey _drawerKey=GlobalKey();
int taskID;
偏置电流偏置;
@凌驾
void initState(){
super.initState();
_后期任务();
}
_后期任务(){
taskID=SchedulerBinding.instance.scheduleFrameCallback((){
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// Your Code Here
});
}
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,
);
}
}
/// create a key for the scaffold in order to access it later.
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(context) {
return WillPopScope(
child: Scaffold(
// assign key (important)
key: _scaffoldKey,
drawer: SideNavigation(),
onWillPop: () async {
// drawer is open then first close it
if (_scaffoldKey.currentState.isDrawerOpen) {
Navigator.of(context).pop();
return false;
}
// we can now close the app.
return true;
});}
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
Scaffold(
key: scaffoldKey,
appBar: ..)
bool opened =scaffoldKey.currentState.isDrawerOpen;
Scaffold(
onDrawerChanged: (isOpened) {
//todo what you need for left drawer
},
onEndDrawerChanged: (isOpened) {
//todo what you need for right drawer
},
)
@override
Widget build(BuildContext context) {
return Scaffold(
onDrawerChanged: (isOpened) {
*//Left drawer, Your code here,*
},
onEndDrawerChanged: (isOpened) {
*//Right drawer, Your code here,*
},
);
}