New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android physical back-button processing method #88
Comments
Version (please complete the following information):
|
Flutter Version: v1.22.1 |
我刚刚试了 |
This is my app.dart: import 'package:flutter/material.dart';
import '../router.dart';
import 'package:provider/provider.dart';
import 'package:bot_toast/bot_toast.dart';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State< MyApp > with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.resumed) {
// ...检版本更新处理;
}
}
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
...
],
child: MaterialApp(
initialRoute: '/',
onGenerateRoute: AppRouter.generate,
navigatorObservers: [AppRouter(), BotToastNavigatorObserver()],
debugShowCheckedModeBanner: false,
builder: (BuildContext context, Widget child) {
child = MediaQuery(
child: child,
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0));
child = (BotToastInit())(context, child);
return child;
},
),
);
}
} ========================================== And this is my router.dart: class AppRouter extends NavigatorObserver {
static AppRouter _router = AppRouter._();
static final Map<String, Function> _configs = {
'/': (BuildContext context, [Object args]) => HomePage(),
'/second': (BuildContext context, [Object args]) => SecondPage(),
};
static final Function generate = (RouteSettings settings) {
final Function builder = _configs[settings.name];
return CupertinoPageRoute(
settings: settings,
builder: (BuildContext context) => settings.arguments == null
? builder(context)
: builder(context, settings.arguments),
);
};
AppRouter._() {
_stream = StreamController.broadcast();
}
factory AppRouter() => _router;
// 当前路由栈
static List<Route> _routes = [];
List<Route> get routes => _routes;
Route get currentRoute => _routes[_routes.length - 1];
String get currentName => currentRoute.settings.name;
// stream相关
static StreamController _stream;
StreamController get stream => _stream;
Future<Object> go(String name, [Object args]) =>
navigator.pushNamed(name, arguments: args);
void pop<T extends Object>([T res]) => navigator.pop(res);
Future<Object> root(String name, [String keep]) =>
navigator.pushNamedAndRemoveUntil(
name, keep != null ? ModalRoute.withName(keep) : (r) => r == null);
Future<Object> replace(String name, [Object args]) =>
navigator.pushReplacementNamed(name, arguments: args);
void popUntil(String name) =>
navigator.popUntil((route) => route.settings.name == name);
/// 当调用[Navigator.push]时
@override
void didPush(Route route, Route previousRoute) {
super.didPush(route, previousRoute);
// 这里过滤push的是dialog的情况
if (route is CupertinoPageRoute || route is MaterialPageRoute) {
_routes.add(route);
routeObserver();
}
}
/// 当调用[Navigator.replace]时
@override
void didReplace({Route newRoute, Route oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (newRoute is CupertinoPageRoute || newRoute is MaterialPageRoute) {
_routes.remove(oldRoute);
_routes.add(newRoute);
routeObserver();
}
}
/// 当调用[Navigator.pop]时
@override
void didPop(Route route, Route previousRoute) {
super.didPop(route, previousRoute);
if (route is CupertinoPageRoute || route is MaterialPageRoute) {
_routes.remove(route);
routeObserver();
}
}
@override
void didRemove(Route removedRoute, Route oldRoute) {
super.didRemove(removedRoute, oldRoute);
if (removedRoute is CupertinoPageRoute ||
removedRoute is MaterialPageRoute) {
_routes.remove(removedRoute);
routeObserver();
}
}
void routeObserver() {
print('路由栈: $routes');
print('当前路由: $currentRoute');
print('当前路由名称: $currentName');
_stream.sink.add(routes);
}
void clear() {
_stream?.close();
routes?.clear();
}
} =========================== |
你尝试使用下面的初始方式 //BotToastInit方法一定不要放在闭包里调用,否则会影响`WidgetsBinding.instance.addObserver`调用的时机
final botToastBuilder = BotToastInit();
MaterialApp(
title: 'BotToast Demo',
builder: (context, child) {
child = myBuilder(context,child); //do something
child = botToastBuilder(context,child);
return child;
},
navigatorObservers: [BotToastNavigatorObserver()], //2. registered route observer
home: XxxxPage(),
) |
我换了你说的初始方式,问题解决了,这是为什么呢? final botToastBuilder = BotToastInit();
MaterialApp(
title: 'BotToast Demo',
builder: (context, child) {
child = myBuilder(context,child); //do something
child = botToastBuilder(context,child);
// child = (BotToastInit())(context, child); 这俩种方式有什么区别?
return child;
},
navigatorObservers: [BotToastNavigatorObserver()], //2. registered route observer
) |
另外我有一个建议:我现在用showAnimationWiget模拟了flutter原生的showBottomSheet,但是在这个Widget里面我有一个选择地址的按钮,这个按钮需要跳转到其他页面,也就是说我希望的效果不是crossPage,而是在当前界面show一个Toast的时候不是crossPage而是Keep(保持)在当前页面,当我push另外页面之后回来的时候toast保持显示,我这样说能明白我说的这个效果吗? |
这是因为 |
你提的这个需求最好是用 |
好的,我知道了,谢谢大佬 |
现在BotToast的组件添加顺序是怎么样的?我现在遇到一个问题:在showAnimationWidget之后如果再showLoading,偶尔会出现showLoading会被showAnimationWidget遮挡住 |
同一组的 |
我这里貌似初步实现了显示顺序的优化,你看一下有没有什么问题: import 'package:bot_toast/src/toast_widget/toast_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void safeRun(void Function() callback) {
SchedulerBinding.instance.addPostFrameCallback((_) {
callback();
});
SchedulerBinding.instance.ensureVisualUpdate();
}
class BotToastManager extends StatefulWidget {
final Widget child;
const BotToastManager({Key key, this.child}) : super(key: key);
@override
BotToastManagerState createState() => BotToastManagerState();
}
class BotToastManagerState extends State<BotToastManager> {
// final Map<String, Map<UniqueKey, Widget>> _map = {};
final List<BotToastWidget> _toasts = [];
final Set<UniqueKey> _pending = Set<UniqueKey>();
/*List<Widget> get _children => _map.values.fold([], (value, items) {
return value..addAll(items.values);
});*/
List<Widget> get _children => _toasts.fold([], (v, e) => v..add(e.widget));
void insert(String groupKey, UniqueKey key, Widget widget) {
safeRun(() {
// _map[groupKey] ??= {};
final uniqueKey = UniqueKey();
widget = ProxyInitState(
initStateCallback: () {
_pending.remove(key);
},
child: widget,
);
widget = ProxyDispose(
key: uniqueKey,
child: widget,
disposeCallback: () {
// _map[groupKey]?.remove(key);
_toasts.removeWhere((e) => e.groupKey == groupKey && e.key == key);
},
);
// _map[groupKey][key] = widget;
_toasts.add(BotToastWidget(groupKey, key, widget));
_pending.add(key);
_update();
});
}
void remove(String groupKey, UniqueKey key) {
safeRun(() {
if (_pending.contains(key)) {
// 首桢渲染完成之前,就被删除,需要确保ProxyDispose被安装,因此要放到下一帧进行删除
return remove(groupKey, key);
} else {
// _map[groupKey]?.remove(key);
_toasts.removeWhere((e) => e.groupKey == groupKey && e.key == key);
_update();
}
});
}
void removeAll(String groupKey) {
safeRun(() {
/*if (_map[groupKey] == null) {
return;
}*/
if (!_toasts.any((e) => e.groupKey == groupKey)) return;
// _map[groupKey].removeWhere((key, _) => !_pending.contains(key));
_toasts.removeWhere((e) => !_pending.contains(e.key));
_update();
/*if (_map[groupKey].isNotEmpty) {
_map[groupKey].forEach((key, value) {
return remove(groupKey, key);
});
}*/
_toasts.forEach((e) {
if (e.groupKey == groupKey) remove(groupKey, e.key);
});
});
}
void cleanAll() {
safeRun(() {
_toasts.removeWhere((e) => !_pending.contains(e.key));
_toasts.forEach((e) => remove(e.groupKey, e.key));
/*_map.forEach((groupKey, value) {
assert(value != null);
value.removeWhere((key, _) => !_pending.contains(key));
if (value.isNotEmpty) {
value.forEach((key, value) {
return remove(groupKey, key);
});
}
});*/
_update();
});
}
void _update() {
if (mounted) {
setState(() {});
}
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
widget.child,
]..addAll(_children),
);
}
}
class BotToastWidget {
final String groupKey;
final UniqueKey key;
final Widget widget;
BotToastWidget(this.groupKey, this.key, this.widget)
: assert(key != null),
assert(groupKey != null),
assert(widget != null);
}
|
我已经改好了,推在dev分支上,谢谢了 :) |
没事,只是我初步实现并运用到了我的项目中,具体有没有问题,还要多测试呢... |
v3.0.5 released |
Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away! |
How to prevent the Route change of the project page when using BackButtonBehavior.ignore and BackButtonBehavior.close?
The current situation is: when I use BotToast.showAnimationWidget on a page and set the backButtonBehavior property to BackButtonBehavior.ignore or BackButtonBehavior.close, Toast is indeed closed, but the page Route also goes back one page.
The text was updated successfully, but these errors were encountered: