firebase - 为什么我的 WillPopScope 只是偶尔在 Flutter 导航中工作是有原因的?
问题描述
我正在编写一个 Flutter 应用程序,它使用我认为可能不是浏览屏幕的正确方式。我正在实现一些提供程序,因此我试图避免声明式 Navigator.push 导航风格,这导致我基本上使用索引来告诉应用程序在任何给定时间显示多个屏幕中的哪个。In the example below, the messages screen is a tab inside an IndexedStack, and when a specific "chat" is selected it changes the messagesIndex, changing the return value from a list of all chats to a display of the specific chat.
列出所有聊天的消息屏幕:
class MessagesScreen extends StatefulWidget {
final Function(bool) hideBottomNavigationBar;
MessagesScreen({@required this.hideBottomNavigationBar});
@override
_MessagesScreenState createState() => _MessagesScreenState();
}
class _MessagesScreenState extends State<MessagesScreen> {
RoseUser roseUser;
Database database = Database();
List<Chat> chats = [];
Chat
selectedChat; // whichever chat the user clicks on, to provide to chat view screen
int messagesIndex = 0; // 0 is messages list, 1 is specific chat
@override
Widget build(BuildContext context) {
DocumentSnapshot roseUserSnap = Provider.of<DocumentSnapshot>(context);
if (roseUserSnap != null) roseUser = RoseUser.fromDatabase(roseUserSnap);
if (messagesIndex == 1)
return ChatViewScreen(selectedChat, updateMessagesIndex: (index) {
setState(() {
messagesIndex = 0;
selectedChat = null;
widget.hideBottomNavigationBar(false);
});
});
return StreamBuilder<QuerySnapshot>(
stream: database.streamChatPreviews(roseUser),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text('Error streaming chat previews'),
);
}
if (snapshot.hasData) {
List<DocumentSnapshot> chatSnaps = snapshot.data.docs;
chats = chatSnaps.map((e) => Chat.fromDatabase(e)).toList();
chats.sort(
(a, b) => b.lastMessage.sentAt.compareTo(a.lastMessage.sentAt));
return ListView.builder(
itemCount: chats.length,
itemBuilder: (context, i) {
Chat chat = chats[i];
return GestureDetector(
onTap: () {
setState(() {
selectedChat = chat;
messagesIndex = 1;
widget.hideBottomNavigationBar(true);
});
},
child: ChatListCard(
chat: chat,
roseUser: roseUser,
));
});
}
return Center(
child: CircularProgressIndicator(),
);
});
}
}
特定聊天的聊天视图屏幕:
class ChatViewScreen extends StatefulWidget {
final Chat chat;
final Function(int) updateMessagesIndex;
ChatViewScreen(this.chat, {@required this.updateMessagesIndex});
@override
_ChatViewScreenState createState() => _ChatViewScreenState();
}
class _ChatViewScreenState extends State<ChatViewScreen> {
Chat chat;
RoseUser roseUser;
Database database = Database();
bool sentMessage = false;
@override
void initState() {
chat = widget.chat;
super.initState();
}
@override
Widget build(BuildContext context) {
DocumentSnapshot roseUserSnap = Provider.of<DocumentSnapshot>(context);
if (roseUserSnap != null) roseUser = RoseUser.fromDatabase(roseUserSnap);
if (roseUser == null)
return Center(
child: CircularProgressIndicator(),
);
return WillPopScope(
onWillPop: () {
widget.updateMessagesIndex(0);
return Future.value(false);
},
child: StreamBuilder<QuerySnapshot>(
stream: database.streamChatMessages(chat.chatId),
builder: (context, snapshot) {
if (snapshot.hasError) {
print(snapshot.error.toString());
return Center();
}
if (snapshot.hasData) {
QuerySnapshot messageDocs = snapshot.data;
chat.messages =
messageDocs.docs.map((e) => Message.fromDatabase(e)).toList();
}
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(chat.title,
style: TextStyle(
fontSize: 18,
)),
IconButton(
icon: Icon(Icons.info),
onPressed: () {
print('go to chat info screen');
})
],
),
),
Expanded(
child: ListView.separated(
reverse: true,
itemCount: chat.messages.length,
itemBuilder: (context, index) {
Message message = chat.messages.toList()[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: message.senderID == roseUser.uid
? MyMessageBubble(message: message)
: MessageBubble(message: message),
);
},
separatorBuilder: (context, index) {
if (index >= chat.messages.length - 1) return Container();
DateTime nextSent = chat.messages[index].sentAt;
DateTime firstSent = chat.messages[index + 1].sentAt;
if (nextSent.difference(firstSent).inHours.abs() >= 24)
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 18.0, vertical: 8),
child: Column(
children: [
Divider(),
Text(DateFormat('MMMM d, yyyy').format(nextSent))
],
),
);
return Container();
},
),
),
Padding(
padding:
const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 8.0),
child: MessageComposer(
onMessageSent: (text) async {
Message message = new Message(
text: text,
sender: roseUser.firstName + ' ' + roseUser.lastName,
sentAt: DateTime.now(),
containsMedia: false,
senderID: roseUser.uid);
setState(() {
chat.messages.add(message);
});
bool sendSuccess =
await database.sendMessage(chat, message);
if (!sendSuccess) {
setState(() {
chat.messages.remove(message);
});
} else {
sentMessage = true;
}
},
),
),
],
);
}),
);
}
}
系统乍一看正常工作,在聊天视图屏幕中,我使用 WillPopScope 捕捉 android 系统返回手势,以便“弹出”回消息列表,实际上只是通过回调将 messagesIndex 更改回 0功能。但是,当我发送一条消息(它调用一个对聊天文档及其消息子集合的 firebase firestore 调用)时,OnWillPop 方法变得完全没有响应,并且系统返回手势根本不会触发任何东西。
我知道我正在使用这个自定义导航系统在 jank 领域进行操作,但我希望能够在这里找出问题而不是处理 Navigator 2.0。如果有人有任何想法,我会全力以赴。
谢谢。
解决方案
推荐阅读
- javascript - @click 没有在 Vue devtools 中注册事件
- java - 获取二元运算符'>'的错误错误操作数类型第一种类型:double []第二种类型:int
- google-play - 如何在我已添加到的 Google Play 商店开发者控制台上离开组织?
- python - 使用 python 快速有效地更新数百万个 MongoDB 文档的技巧?
- security - 如何从 JWT 令牌中获取数据并继续在客户端上请求它?.Net 核心
- java - 如何将(某些)Unicode 简化为 ASCII?
- javascript - 如何在没有表单的情况下传递 POST 变量?
- scala - 如何在 Scala 中避免/修复错误“java.io.Serializable”
- python - 如何修复 tkinter 按钮图像填充角落?
- html - 如何在行下创建带有小潜台词的可填充下划线文本