您好, 我有一个非常具体的问题要问。我必须用步骤和图片来解释它,所以它们就在那里。 我有一个包含三个屏幕的应用:
而且它们都是 PageView 的一部分。这个 PageView 类是在一个叫做 main_tab_controller.dart 的类中控制的。在该类中,在 initState() 中,我有一个 Firebase Messaging 方法,每次收到通知 (onMessage) 时都会调用该方法。因此,每次收到此通知时,我都会显示如下所示的叠加层。
它在这三个主屏幕上完美运行。如果是聊天通知,我会将 PageView 定向到第二个屏幕,即 MainChatAndRequest 屏幕,然后打开聊天屏幕。如果是请求通知,我会将 PageView 定向到第二个屏幕,即 MainChatAndRequest 屏幕,并打开请求屏幕。
但我遇到的问题如下。在我的 MainFeedScreen 和 MainProfileScreen 中,我打开了一些其他屏幕。例如在 MainFeedScreen 中,我打开 UserDetailsScreen 或 FilterScreen。或者在 MainProfileScreen 中,我打开 SettingsScreen 或 EditUserProfileScreen。
所以我的问题是:例如,如果我导航到 MainProfileScreen 并在该屏幕中打开 SettingsScreen,并且我收到覆盖顶部消息,我该如何关闭当前打开的 SettingsScreen 并导航回第二个屏幕,即 MainChatsAndRequestsScreen来自位于 main_tab_controller.dart 的 initState() 中的 Firebase 消息传递函数,它是所有其他屏幕的父级。 你有下面的图片:
我已经尝试了所有方法,Navigator.popUntil(context)、Navigator.pushReplacement(context)、使用 Navigator.pushNamed(context) 但没有任何效果。如果有人可以帮助我,将不胜感激。
只是为了让您更好地了解屏幕: 父屏幕是具有三个屏幕的 PageView:
然后在主供稿屏幕中您有:
在主聊天和请求屏幕中,您有两个 TabBar 屏幕:
在主配置文件屏幕中,您有:
PageView 代码片段:
@override
void initState() {
pageController = PageController(initialPage: _currentIndex);
chatAndRequestController = TabController(length: 2, vsync: this);
var chatAndRequestProvider =
Provider.of<ChatAndRequestProvider>(context, listen: false);
super.initState();
fbm.requestNotificationPermissions();
fbm.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
bool isRequest;
var mode = (Platform.isIOS) ? message['mode'] : message['data']['mode'];
var imageUrl = '';
switch (mode) {
case 'chat':
isRequest = false;
imageUrl =
chatAndRequestProvider.chatsList.first[kProfilePictureUrl];
break;
case 'sentRequest':
isRequest = true;
imageUrl = (Platform.isIOS)
? message['profilePictureUrl']
: message['data']['profilePictureUrl'];
break;
case 'acceptRequest':
isRequest = false;
imageUrl = (Platform.isIOS)
? message['profilePictureUrl']
: message['data']['profilePictureUrl'];
break;
default:
isRequest = false;
break;
}
AudioCache player = new AudioCache();
const alarmAudioPath = "sounds/notification_sound.mp3";
player.play(alarmAudioPath);
print('Show this ting');
if (_currentIndex != 1) {
if (!isDialogOpen) {
isDialogOpen = true;
_showAnimatedBox(
context,
(Platform.isIOS)
? message['aps']['alert']['title']
: message['notification']['title'],
(Platform.isIOS)
? message['aps']['alert']['body']
: message['notification']['body'],
imageUrl,
isRequest,
);
}
}
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
},
);
notificationPlugin
.setListenerForLowerVersions(onNotificationInLowerVersions);
notificationPlugin.setOnNotificationClick(onNotificationClick);
_children.addAll([
MainFeedScreen(
analytics: widget.analytics,
observer: widget.observer,
latitude: widget.latitude,
longitude: widget.longitude,
),
MainChatAndRequestScreen(
analytics: widget.analytics,
observer: widget.observer,
pageContoller: chatAndRequestController,
),
MainProfileScreen(analytics: widget.analytics, observer: widget.observer),
]);
}
Future _showAnimatedBox(context, topText, bottomText, imageUrl, isRequest) {
showDialog(
context: context,
builder: (BuildContext builderContext) {
_timer = Timer(Duration(seconds: 4), () {
Navigator.of(context).pop();
isDialogOpen = false;
});
return Dismissible(
key: Key('dismissible'),
direction: DismissDirection.up,
onDismissed: (_) {
Navigator.of(context).pop();
isDialogOpen = false;
},
child: FunkyNotification(
() {
var chatAndRequestProvider =
Provider.of<ChatAndRequestProvider>(context, listen: false);
// var contextProv =
// Provider.of<ContextProvider>(context, listen: false);
chatAndRequestProvider.setAreThereNewChatsAndRequestFalse();
if (isRequest) {
pageController.jumpToPage(1);
chatAndRequestController.animateTo(1);
Navigator.of(context).pop();
// Navigator.of(contextProv.context).pop();
// SystemChannels.platform.invokeMethod('SystemNavigator.pop');
// Navigator.popUntil(
// context,
// ModalRoute.withName('/mainProfileScreen'),
// );
// Navigator.of(context)
// .popUntil(ModalRoute.withName('/mainProfileScreen'));
// Navigator.pushAndRemoveUntil(
// context,
// MaterialPageRoute(
// builder: (BuildContext context) => MainTabBarController(
// analytics: null,
// observer: null,
// latitude: 100.23423234,
// longitude: 12.324234234,
// isProfileBlocked: false,
// isVersionGood: true,
// ),
// ),
// (route) => true,
// );
} else {
var chatAndRequestProvider =
Provider.of<ChatAndRequestProvider>(context,
listen: false);
pageController.jumpToPage(1);
chatAndRequestController.animateTo(0);
Navigator.of(context).pop();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatScreen(
appMode:
chatAndRequestProvider.chatsList.first[kAppMode],
peerId: chatAndRequestProvider.chatsList.first[kUserId],
peerAvatar: chatAndRequestProvider
.chatsList.first[kProfilePictureUrl],
peerName: chatAndRequestProvider
.chatsList.first[kNameAndSurname],
friendshipStatus: chatAndRequestProvider
.chatsList.first['friendsStatus'],
analytics: widget.analytics,
observer: widget.observer,
),
),
);
}
},
topText,
bottomText,
imageUrl,
),
);
}).then((val) {
if (_timer.isActive) {
_timer.cancel();
}
isDialogOpen = false;
});
}
答案 0 :(得分:1)
我会尽量使我的回答笼统,以便其他人更容易跟进。
简而言之,问题在于您有一组嵌套的屏幕分布在一组浏览量之间,并且您希望在来自外部事件(在本例中为叠加层)的浏览量之间切换。
下面是一个例子:
我无法提供完整代码,因为我没有您的完整源代码。但这里有一个例子?
注意:此示例使用 Provider。
示例事件代码
// Remove all the screens in the route
Navigator.of(context).popUntil((route) => route.isFirst); // If the screen is not the first replace the check
// Change the second pageview page
Provider.of<ChatSelectPageView>(context, listen: false).setPage(selectedSecondPageViewPage);
// In case it is required to add intermediate screens between the first and the second pageview it must be added here
// Change the main pageview page
_mainPageViewcontroller.animateToPage(1);
第二页浏览
// Reads the page index present in the provider
int selectedPage = Provider.of<ChatSelectPageView>(context, listen: false).page;
// Changes to the cotroller page to the selected page
_pageController.jumpToPage(selectedPage);
ChatSelectPageView
class ChatSelectPageView extends ChangeNotifier {
int page = 0;
void setPage(int _page) {
page = _page;
// Depending on your implementation it might be better to remove this line to reduce the number of builds
notifyListeners();
}
}
为了实现所需的行为,有多种方法可以实现。如果我们想坚持您的实施,我们将受到一些限制。但是在这种情况下,我建议您使用某种全局状态管理库,例如提供程序,无需任何库即可完成,但状态很快就会变得非常混乱。
正如您上面提到的,您尝试了 Navigator.popUntil
但它没有用,我怀疑这是因为您提供了错误的上下文。由于 Navigator.**** 依赖于上下文才能工作,即要弹出屏幕,您必须提供其上下文。或者路由检查错误。
此代码将写入外部事件中,在您的情况下,它将写入叠加层的点击侦听器中。
使用状态管理解决方案(例如 Provider)将状态传递给主页面视图的后代,向下传递到屏幕。此提供程序的类型为 ChangeNotifierProvider
。单击叠加层时,将设置一个标志为所需的综合浏览量页面索引(我说的是第二次综合浏览量)。在您的情况下,此标志用于选择聊天或请求。
完成后,您调用 Navigator.of(context).popUntil((route) => route.isFirst);
假设综合浏览量出现在您应用的第一页上。如果它不在该页面上,您将不得不使用带有自定义逻辑的 Navigator.of(context).popUntil()
。
之后,我们将不得不导航回第二个综合浏览量,或者在您的情况下将第一个综合浏览量更改为第二个页面。由于我们之前更改了 provider 中的标志,因此第二个页面浏览将已经切换。