我怎样才能在模态底部 sheet 中执行 Navigator.push (不是父页面)
How can i do Navigator.push in a modal bottom sheet only (not the parent page)
在我的应用程序中,我正在尝试创建一个评论部分。在本节中,我希望用户能够以类似于 YouTube 应用程序的方式回复另一个用户的评论。我已经成功地创建了一个模式底部 sheet 来显示顶级评论并且在几个流构建器的帮助下它工作得很好。但是,我面临的问题是二级评论(回复人们的评论。)。我想做到这一点,以便用户点击评论并被带到一个页面(仍在模式底部 sheet),在那里他可以看到对评论的所有回复,也可以自己发表评论,如果他按下返回,他会直接回到原来的位置,并可以继续滚动浏览顶级评论。
类似于 YouTube 应用的外观。
我想在底部 sheet 中使用 Navigator.push,在模态底部 sheet 中的当前现有页面之上叠加一个新页面,并在这个新页面中,第二层要显示特定评论的评论(回复)。但是,当我调用 Navigator.push 时,整个页面都会发生变化。整个父页面转移到新页面,而不仅仅是底部的内容 sheet。所以,这是我的问题。我乐于接受想法。
我评论底下的代码sheet:
showModalBottomSheet(
context: context,
builder: (context) {
return
Container(
child: StatefulBuilder(
builder: (BuildContext context, setTheModalState) {
setModalState = setTheModalState;
return Container(
child: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(listview))])}))}
这是我目前设计的。现在棘手的一点是在按下回复按钮(消息图标)
时在模态 sheet 中创建一个新页面
这就是 YouTube 评论系统的样子。
评论区代码:
showModalBottomSheet(
context: context,
builder: (context) {
return
Container(
child: StatefulBuilder(
builder: (BuildContext context, setTheModalState) {
setModalState = setTheModalState;
return Container(
child: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: Firestore.instance
.collection("Replies")
.document(dream.documentID)
.collection(dream.documentID)
.orderBy('time', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: SpinKitDoubleBounce(
color: Colors.blue,
),
);
} else {
dynamic replies = snapshot.data.documents;
return ListView.builder(
itemCount: replies.length,
reverse: true,
itemBuilder: (context, index) {
if (replies[index]["text"] != "" &&
replies[index]["images"] == null) {
return _buildStringCommment(
replies[index], true);
} else {
if (replies[index]["images"].length == 1) {
return _buildCommentFromOneImage(
replies[index], true);
} else {
if (replies[index]["images"].length == 2) {
return _buildCommentFromTwoImages(
replies[index], true);
} else {
if (replies[index]["images"].length ==
3) {
return _buildCommentFromThreeImages(
replies[index], true);
} else {
if (replies[index]["images"].length ==
4) {
return _buildCommentFromFourImages(
replies[index], true);
} else {
if (replies[index]["images"].length ==
5) {
return _buildCommmentFromFiveImages(
replies[index], true);
} else {
return _buildMessageFromMoreThanFiveImages(
replies[index], true);
}
}
}
}
}
}
},
);
}
},
),
),
theTypeReplyThingie(dream, context, true)
],
),
);
},
),
);
},
);
“type reply thingie”是具有文本输入表单和发送按钮的小部件。
您必须使用 showModalBottomSheet() 方法,这将 return 您想要的评论部分。
示例代码是:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatelessWidget(),
),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
MyStatelessWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
RaisedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
)
],
),
),
);
},
);
},
),
);
}
}
更多信息,请访问:https://api.flutter.dev/flutter/material/showModalBottomSheet.html
有两种方法可以实现这一点。
如果你用的是modalSheet,那为什么还要用Navigator.push?比方说,您有一个评论文本 field/button。在onPressed回调中,需要调用showModalSheet。你不需要路由。
`Inkwell(child: Text("comment"),
onTap: () => showModalSheet() //your sheet here
) `
您可以在 MaterialPageRoute 中使用 fullScreenDailog 属性。这样会更符合你的要求。
Navigator.of(context).push(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => XYZ(),)
你好,我认为你需要在底部导航sheet,因为它发生在普通页面中,你可以继续的一种方法是使用下面的代码,只要测试一下这段代码,我希望它能工作,谢谢。
每当需要打开 sheet
时调用 openbottomsheet
void opensheet() async {
showModalBottomSheet(
context: (context),
enableDrag: true,
isDismissible: true,
builder: (context) {
return Page1();
});
}
}
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
int currentview = 0;
List<Widget> pages;
@override
void initState() {
pages = [
page1(),
page2(),
];
super.initState();
}
@override
Widget build(BuildContext context) {
return pages[currentview];
}
Widget page1() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60))),
height: 400,
width: double.maxFinite,
child: Center(
child: InkWell(
onTap: () {
setState(() {
currentview = 1;
});
},
child: RaisedButton(
child: Text("click to navigate"),
),
),
),
);
}
Widget page2() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60))),
height: 400,
width: double.maxFinite,
child: Center(
child: InkWell(
onTap: () {
setState(() {
currentview = 0;
});
},
child: Text("click to move back"),
),
),
);
}
}
控制父页面上的后退按钮,底部 sheet 用 willpopscope
包围脚手架
willpopscope(
onwillpopscope:(){
//check if bottomsheet is open or not this may be hard to listen the state of bottomsheet let me try it
if(bottomsheetisopen){
//set the bottomsheet currentindex to 0 for initial page
return Future.value(false);
}else{
return Future.value(true);
}
}
child:Scaffold()
)
同时尝试 bottomsheet 和 modalbottom sheet 其中一个提供监听器来监听 sheet 打开或关闭的状态
太棒了,为了其他可能有相同查询的人的利益,我已经设法使用 Azad Prajapat 先生的答案的修改版本来做到这一点。我在下面附上相关代码。
本质上,我使用堆栈来显示高度为 0 的大小框或显示具有流生成器、文本表单和 reply_to_a_comment 页面的其他相关小部件的容器。使用布尔值,我可以轻松地在用户看到的内容之间切换,而无需重新加载整个评论页面,也无需用户丢失当前的滚动位置。
PS: 我是flutter的初学者,所以,有些代码看起来太样板了。请耐心等待。
新评论区代码:
wereOnTopLevel = true;
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
child: StatefulBuilder(
builder: (BuildContext context, setTheModalState) {
setModalState = setTheModalState;
return Stack(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: Firestore.instance
.collection("Replies")
.document(post.documentID)
.collection(post.documentID)
.orderBy('time', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: SpinKitDoubleBounce(
color: Colors.blue,
),
);
} else {
dynamic replies = snapshot.data.documents;
return ListView.builder(
itemCount: replies.length,
reverse: true,
itemBuilder: (context, index) {
if (replies[index]["text"] != "" &&
replies[index]["images"] == null) {
return _buildStringReply(
replies[index], true, true);
} else {
if (replies[index]["images"].length ==
1) {
return _buildMessageFromOneImage(
replies[index], true, true);
} else {
if (replies[index]["images"].length ==
2) {
return _buildMessageFromTwoImages(
replies[index], true, true);
} else {
if (replies[index]["images"].length ==
3) {
return _buildMessageFromThreeImages(
replies[index], true, true);
} else {
if (replies[index]["images"]
.length ==
4) {
return _buildMessageFromFourImages(
replies[index], true, true);
} else {
if (replies[index]["images"]
.length ==
5) {
return _buildMessageFromFiveImages(
replies[index], true, true);
} else {
return _buildMessageFromMoreThanFiveImages(
replies[index], true, true);
}
}
}
}
}
}
},
);
}
},
),
),
theTypeReplyThingie(dream, context, true)
],
),
),
wereOnTopLevel
? SizedBox(
height: 0,
)
: showTheRepliesToCommentsThing(
dream, context, idYaComment, commentInfo)
],
);
},
),
);
},
);
wereOnTopLevel 是一个布尔值,它告诉底部 sheet 用户是否在某个评论上点击了“回复评论”按钮。
theTypeReplyThing 是包含 textFormField、表情符号网格、用于显示所选图像网格的容器、发送按钮和用于将图像附加到回复/评论的按钮。
showTheRepliesToTheCommentsThing 是包含回复的小部件。它或多或少与评论页面相同,除了它,我在顶部放了一个正在回复的评论的小预览,我不得不将容器的颜色设为白色,因为它是透明的并且这看起来很混乱。
让我附上 reply_to_a_comment 页面的图片以显示差异。 (后来我在顶部栏下方添加了一个分隔线。让它看起来更好)
将它与我附加到问题的评论部分的图像进行对比。
只需在主表中显示另一个 ModalBottomSheet
这是一个例子,
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
child: Center(
child: ElevatedButton(
child: Text('back'),
onPressed: () =>
Navigator.pop(context),
),
),
);
});
},
child: Text('Next Bottom'));
});
},
child: Text('press Me'),
)
在我的应用程序中,我正在尝试创建一个评论部分。在本节中,我希望用户能够以类似于 YouTube 应用程序的方式回复另一个用户的评论。我已经成功地创建了一个模式底部 sheet 来显示顶级评论并且在几个流构建器的帮助下它工作得很好。但是,我面临的问题是二级评论(回复人们的评论。)。我想做到这一点,以便用户点击评论并被带到一个页面(仍在模式底部 sheet),在那里他可以看到对评论的所有回复,也可以自己发表评论,如果他按下返回,他会直接回到原来的位置,并可以继续滚动浏览顶级评论。
类似于 YouTube 应用的外观。 我想在底部 sheet 中使用 Navigator.push,在模态底部 sheet 中的当前现有页面之上叠加一个新页面,并在这个新页面中,第二层要显示特定评论的评论(回复)。但是,当我调用 Navigator.push 时,整个页面都会发生变化。整个父页面转移到新页面,而不仅仅是底部的内容 sheet。所以,这是我的问题。我乐于接受想法。
我评论底下的代码sheet:
showModalBottomSheet(
context: context,
builder: (context) {
return
Container(
child: StatefulBuilder(
builder: (BuildContext context, setTheModalState) {
setModalState = setTheModalState;
return Container(
child: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(listview))])}))}
这是我目前设计的。现在棘手的一点是在按下回复按钮(消息图标)
时在模态 sheet 中创建一个新页面这就是 YouTube 评论系统的样子。
评论区代码:
showModalBottomSheet(
context: context,
builder: (context) {
return
Container(
child: StatefulBuilder(
builder: (BuildContext context, setTheModalState) {
setModalState = setTheModalState;
return Container(
child: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: Firestore.instance
.collection("Replies")
.document(dream.documentID)
.collection(dream.documentID)
.orderBy('time', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: SpinKitDoubleBounce(
color: Colors.blue,
),
);
} else {
dynamic replies = snapshot.data.documents;
return ListView.builder(
itemCount: replies.length,
reverse: true,
itemBuilder: (context, index) {
if (replies[index]["text"] != "" &&
replies[index]["images"] == null) {
return _buildStringCommment(
replies[index], true);
} else {
if (replies[index]["images"].length == 1) {
return _buildCommentFromOneImage(
replies[index], true);
} else {
if (replies[index]["images"].length == 2) {
return _buildCommentFromTwoImages(
replies[index], true);
} else {
if (replies[index]["images"].length ==
3) {
return _buildCommentFromThreeImages(
replies[index], true);
} else {
if (replies[index]["images"].length ==
4) {
return _buildCommentFromFourImages(
replies[index], true);
} else {
if (replies[index]["images"].length ==
5) {
return _buildCommmentFromFiveImages(
replies[index], true);
} else {
return _buildMessageFromMoreThanFiveImages(
replies[index], true);
}
}
}
}
}
}
},
);
}
},
),
),
theTypeReplyThingie(dream, context, true)
],
),
);
},
),
);
},
);
“type reply thingie”是具有文本输入表单和发送按钮的小部件。
您必须使用 showModalBottomSheet() 方法,这将 return 您想要的评论部分。
示例代码是:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatelessWidget(),
),
);
}
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatelessWidget {
MyStatelessWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
RaisedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
)
],
),
),
);
},
);
},
),
);
}
}
更多信息,请访问:https://api.flutter.dev/flutter/material/showModalBottomSheet.html
有两种方法可以实现这一点。
如果你用的是modalSheet,那为什么还要用Navigator.push?比方说,您有一个评论文本 field/button。在onPressed回调中,需要调用showModalSheet。你不需要路由。
`Inkwell(child: Text("comment"), onTap: () => showModalSheet() //your sheet here ) `
您可以在 MaterialPageRoute 中使用 fullScreenDailog 属性。这样会更符合你的要求。
Navigator.of(context).push( MaterialPageRoute( fullscreenDialog: true, builder: (context) => XYZ(),)
你好,我认为你需要在底部导航sheet,因为它发生在普通页面中,你可以继续的一种方法是使用下面的代码,只要测试一下这段代码,我希望它能工作,谢谢。 每当需要打开 sheet
时调用 openbottomsheet void opensheet() async {
showModalBottomSheet(
context: (context),
enableDrag: true,
isDismissible: true,
builder: (context) {
return Page1();
});
}
}
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
int currentview = 0;
List<Widget> pages;
@override
void initState() {
pages = [
page1(),
page2(),
];
super.initState();
}
@override
Widget build(BuildContext context) {
return pages[currentview];
}
Widget page1() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60))),
height: 400,
width: double.maxFinite,
child: Center(
child: InkWell(
onTap: () {
setState(() {
currentview = 1;
});
},
child: RaisedButton(
child: Text("click to navigate"),
),
),
),
);
}
Widget page2() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60))),
height: 400,
width: double.maxFinite,
child: Center(
child: InkWell(
onTap: () {
setState(() {
currentview = 0;
});
},
child: Text("click to move back"),
),
),
);
}
}
控制父页面上的后退按钮,底部 sheet 用 willpopscope
包围脚手架 willpopscope(
onwillpopscope:(){
//check if bottomsheet is open or not this may be hard to listen the state of bottomsheet let me try it
if(bottomsheetisopen){
//set the bottomsheet currentindex to 0 for initial page
return Future.value(false);
}else{
return Future.value(true);
}
}
child:Scaffold()
)
同时尝试 bottomsheet 和 modalbottom sheet 其中一个提供监听器来监听 sheet 打开或关闭的状态
太棒了,为了其他可能有相同查询的人的利益,我已经设法使用 Azad Prajapat 先生的答案的修改版本来做到这一点。我在下面附上相关代码。
本质上,我使用堆栈来显示高度为 0 的大小框或显示具有流生成器、文本表单和 reply_to_a_comment 页面的其他相关小部件的容器。使用布尔值,我可以轻松地在用户看到的内容之间切换,而无需重新加载整个评论页面,也无需用户丢失当前的滚动位置。 PS: 我是flutter的初学者,所以,有些代码看起来太样板了。请耐心等待。
新评论区代码:
wereOnTopLevel = true;
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
child: StatefulBuilder(
builder: (BuildContext context, setTheModalState) {
setModalState = setTheModalState;
return Stack(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: Firestore.instance
.collection("Replies")
.document(post.documentID)
.collection(post.documentID)
.orderBy('time', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: SpinKitDoubleBounce(
color: Colors.blue,
),
);
} else {
dynamic replies = snapshot.data.documents;
return ListView.builder(
itemCount: replies.length,
reverse: true,
itemBuilder: (context, index) {
if (replies[index]["text"] != "" &&
replies[index]["images"] == null) {
return _buildStringReply(
replies[index], true, true);
} else {
if (replies[index]["images"].length ==
1) {
return _buildMessageFromOneImage(
replies[index], true, true);
} else {
if (replies[index]["images"].length ==
2) {
return _buildMessageFromTwoImages(
replies[index], true, true);
} else {
if (replies[index]["images"].length ==
3) {
return _buildMessageFromThreeImages(
replies[index], true, true);
} else {
if (replies[index]["images"]
.length ==
4) {
return _buildMessageFromFourImages(
replies[index], true, true);
} else {
if (replies[index]["images"]
.length ==
5) {
return _buildMessageFromFiveImages(
replies[index], true, true);
} else {
return _buildMessageFromMoreThanFiveImages(
replies[index], true, true);
}
}
}
}
}
}
},
);
}
},
),
),
theTypeReplyThingie(dream, context, true)
],
),
),
wereOnTopLevel
? SizedBox(
height: 0,
)
: showTheRepliesToCommentsThing(
dream, context, idYaComment, commentInfo)
],
);
},
),
);
},
);
wereOnTopLevel 是一个布尔值,它告诉底部 sheet 用户是否在某个评论上点击了“回复评论”按钮。
theTypeReplyThing 是包含 textFormField、表情符号网格、用于显示所选图像网格的容器、发送按钮和用于将图像附加到回复/评论的按钮。
showTheRepliesToTheCommentsThing 是包含回复的小部件。它或多或少与评论页面相同,除了它,我在顶部放了一个正在回复的评论的小预览,我不得不将容器的颜色设为白色,因为它是透明的并且这看起来很混乱。
让我附上 reply_to_a_comment 页面的图片以显示差异。 (后来我在顶部栏下方添加了一个分隔线。让它看起来更好)
将它与我附加到问题的评论部分的图像进行对比。
只需在主表中显示另一个 ModalBottomSheet 这是一个例子,
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
child: Center(
child: ElevatedButton(
child: Text('back'),
onPressed: () =>
Navigator.pop(context),
),
),
);
});
},
child: Text('Next Bottom'));
});
},
child: Text('press Me'),
)