Flutter 如何执行Navigator.push操作?仅在模式底部工作表中(而不是父页面)
在我的应用程序中,我正在尝试创建一个评论部分。在本节中,我希望用户能够以类似于YouTube应用程序的方式回复其他用户的评论。我已经设法创建了一个显示顶级评论的模式底部表单,在几个流生成器的帮助下,它运行得非常好。然而,我面临的问题是对人们评论的二级回复。。我想这样做,用户点击一条评论,并被带到一个页面,仍然在模式的底部页,在那里他看到所有回复的评论,也可以自己评论,如果他按下返回键,他会直接返回到他所在的位置,并可以继续滚动浏览顶级评论 类似于YouTube应用程序的外观。 我的想法是在底部工作表中使用Navigator.push,在模式底部工作表中的当前页面顶部覆盖一个新页面,在这个新页面中,将显示针对特定评论的第二级评论回复。但是,当我调用Navigator.push时,整个页面都会更改。整个父页面移到新页面,而不仅仅是底部工作表中的内容。这就是我的问题。我乐于接受各种想法 我的评论底页后面的代码:Flutter 如何执行Navigator.push操作?仅在模式底部工作表中(而不是父页面),flutter,flutter-layout,flutter-navigation,Flutter,Flutter Layout,Flutter Navigation,在我的应用程序中,我正在尝试创建一个评论部分。在本节中,我希望用户能够以类似于YouTube应用程序的方式回复其他用户的评论。我已经设法创建了一个显示顶级评论的模式底部表单,在几个流生成器的帮助下,它运行得非常好。然而,我面临的问题是对人们评论的二级回复。。我想这样做,用户点击一条评论,并被带到一个页面,仍然在模式的底部页,在那里他看到所有回复的评论,也可以自己评论,如果他按下返回键,他会直接返回到他所在的位置,并可以继续滚动浏览顶级评论 类似于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(listview))])}))}
这就是我迄今为止所设计的。现在需要技巧的一点是,按下回复按钮和消息图标,在模式表中创建一个新页面
这就是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)
],
),
);
},
),
);
},
);
类型reply thingie是具有文本输入表单和发送按钮的小部件。您必须使用showModalBottomSheet方法,该方法将返回所需的注释部分 示例代码是:
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),
)
],
),
),
);
},
);
},
),
);
}
}
有关更多信息,请访问:您必须使用showModalBottomSheet方法,该方法将返回所需的注释部分 示例代码是:
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),
)
],
),
),
);
},
);
},
),
);
}
}
有关更多信息,请访问:有两种方法可以实现此目的 如果您使用的是modalSheet,那么为什么需要使用Navigator.push?比如说,您有一个注释文本字段/按钮。要调用onPressed回调,需要调用showModalSheet。你不需要走路线
`Inkwell(child: Text("comment"),
onTap: () => showModalSheet() //your sheet here
) `
您可以在MaterialPage路由中使用fullScreenDailog属性。这将更适合您的要求
Navigator.of(context).push(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => XYZ(),)
有两种方法可以实现这一点 如果您使用的是modalSheet,那么为什么需要使用Navigator.push?比如说,您有一个注释文本字段/按钮。要调用onPressed回调,需要调用showModalSheet。你不需要走路线
`Inkwell(child: Text("comment"),
onTap: () => showModalSheet() //your sheet here
) `
您可以在MaterialPage路由中使用fullScreenDailog属性。这将更适合您的要求
Navigator.of(context).push(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => XYZ(),)
您好,我想您需要在底部页面内导航,因为它发生在正常页面中。您可以继续的一种方法是使用下面的代码,只要测试一下这段代码,我希望它能工作,谢谢。 在需要打开工作表时调用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"),
),
),
);
}
}
尝试bottomsheet和ModalBottomSheet其中一个提供了一个监听器来监听工作表的状态,无论它是打开的还是关闭的您好,我想您需要在底部工作表中导航,就像在正常页面中一样。您可以继续的一种方法是使用下面的代码,只要测试一下这个代码,我希望它能工作,谢谢。 在需要打开工作表时调用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"),
),
),
);
}
}
试一下bottomsheet和modalbottom sheet其中一个可以让听众听到sheet的状态,不管它是打开的还是关闭的。我在下面附上相关代码 本质上,我使用了一个堆栈来显示高度为0的大小的框,或者显示一个容器,该容器包含流生成器、文本表单和回复到注释页面的其他相关小部件。使用布尔值,我能够轻松地在用户看到的内容之间切换,而无需重新加载整个评论页面,也无需用户丢失当前的滚动位置。 PS:我相对来说是颤振的初学者,所以,有些代码看起来可能太简单了。请容忍我 新的通信段代码:
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是一个布尔值,它告诉底部工作表用户是否点击了某条注释上的ReplyToAccomment按钮
TypeReplything是一个小部件,它包含TextForm字段、表情符号网格、用于显示所选图像网格的容器、发送按钮和用于将图像附加到回复/评论的按钮
ShowTheRepliesToCommentSthing是包含回复的小部件。它与评论页面大致相同,只是我在顶部放了一个回复评论的小预览,我不得不将容器的颜色设置为白色,因为它是透明的,看起来很混乱
让我附上一张回复的图片
显示差异的页面。稍后,我在顶部栏下方添加了分隔符。让它看起来更漂亮
将其与问题所附评论部分的图像进行对比。
所以,为了其他任何可能有同样疑问的人的利益,我已经设法使用Azad Prajapat先生答案的修改版本来实现这一点。我在下面附上相关代码 本质上,我使用了一个堆栈来显示高度为0的大小的框,或者显示一个容器,该容器包含流生成器、文本表单和回复到注释页面的其他相关小部件。使用布尔值,我能够轻松地在用户看到的内容之间切换,而无需重新加载整个评论页面,也无需用户丢失当前的滚动位置。 PS:我相对来说是颤振的初学者,所以,有些代码看起来可能太简单了。请容忍我 新的通信段代码:
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是一个布尔值,它告诉底部工作表用户是否点击了某条注释上的ReplyToAccomment按钮
TypeReplything是一个小部件,它包含TextForm字段、表情符号网格、用于显示所选图像网格的容器、发送按钮和用于将图像附加到回复/评论的按钮
ShowTheRepliesToCommentSthing是包含回复的小部件。它与评论页面大致相同,只是我在顶部放了一个回复评论的小预览,我不得不将容器的颜色设置为白色,因为它是透明的,看起来很混乱
让我附上一张回复到评论页面的图片,以显示区别。稍后,我在顶部栏下方添加了分隔符。让它看起来更漂亮
将其与问题所附评论部分的图像进行对比。
我想你还不太明白我的问题。我已经设法显示了底部的表单和第一级的评论。但我希望当用户点击一条评论时,他会被带到底部页面中的一个新页面,在那里会显示对该评论的回复。要了解我的意思,请查看youtube应用程序。他们的评论系统和我正在做的很相似。我已经创建了底部的工作表,并发表了顶层评论。我搞不懂的是如何使用Navigator.push在模式工作表中创建一个新页面来显示对评论的回复。很抱歉。我意识到我对这个问题的措辞不恰当。请查收。我对它进行了编辑,更清楚地说明了我想做什么。我想你还没有完全理解我的问题。我已经设法显示了底部的表单和第一级的评论。但我希望当用户点击一条评论时,他会被带到底部页面中的一个新页面,在那里会显示对该评论的回复。要了解我的意思,请查看youtube应用程序。他们的评论系统和我正在做的很相似。我已经创建了底部的工作表,并发表了顶层评论。我搞不懂的是如何使用Navigator.push在模式工作表中创建一个新页面来显示对评论的回复。很抱歉。我意识到我对这个问题的措辞不恰当。请查收。我编辑了它,更清楚地说明了我想做什么。让我进一步澄清这个问题。我已经设法显示了底部的表单和第一级的评论。但我希望当用户点击一条评论时,他会被带到底部页面中的一个新页面,在那里会显示对该评论的回复。要了解我的意思,请查看youtube应用程序。他们的评论系统和我正在做的很相似。我已经创建了底部的工作表,并发表了顶层评论。我搞不懂的是如何使用Navigator.push在模式工作表中创建一个新页面,在其中显示对评论的回复。让我进一步澄清这个问题。我已经设法显示了底部的表单和第一级的评论。但我希望当用户点击一条评论时,他会被带到底部页面中的一个新页面,在那里会显示对该评论的回复。要了解我的意思,请查看youtube应用程序。他们的评论系统和我正在做的很相似。我已经创建了底部的工作表,并发表了顶层评论。我搞不懂的是如何使用Navigator.push在模式工作表中创建一个新页面来显示对评论的回复。这看起来非常有希望。我会尝试一下,让你知道我已经测试过了,它确实有效。然而,它也存在一些问题。当用户在第二级评论页面上并按下“后退”按钮时,底部的页面关闭,而不是将他带回到第一级,即使我放置了一个按钮将用户带回到顶级评论页面,它会一直滚动到底部,这可能不是令人愉快的用户体验。因此,如果我们不想在用户按下“后退”按钮时关闭底页,请在父窗口小部件中使用willpopscope属性,以防底页为o
笔您将返回false并将当前值更改为0,或者您可以说初始页面的索引我将在控制返回按钮上使用更多代码更新答案。哦,我已经通过稍微修改您的答案来实现我想要的。我将保存有状态构建器中顶级注释的容器包装成一个堆栈,并使用名为weAreOnTheTopLevelComments的bool,将其设置为显示高度为0的大小框(当我们在顶级注释上时)或包含对给定注释的所有回复的容器。因此,本质上,当用户点击“回复到评论”按钮时,他只需将该布尔值设置为true,并设置流生成器和回复页面上其他小部件使用的一些变量。这看起来非常有希望。我会尝试一下,让你知道我已经测试过了,它确实有效。然而,它也存在一些问题。当用户在第二级评论页面上并按下“后退”按钮时,底部的页面关闭,而不是将他带回到第一级,即使我放置了一个按钮将用户带回到顶级评论页面,它会一直滚动到底部,这可能不是令人愉快的用户体验。因此,如果我们不想在用户按下“后退”按钮时关闭底页,请在父窗口小部件中使用willpopscope属性,如果底页打开,您将返回false并将当前值更改为0,或者您可以说初始页的索引i will用更多的控制返回按钮的代码更新答案哦,我已经通过稍微修改你的答案实现了我想要的。我将保存有状态构建器中顶级注释的容器包装成一个堆栈,并使用名为weAreOnTheTopLevelComments的bool,将其设置为显示高度为0的大小框(当我们在顶级注释上时)或包含对给定注释的所有回复的容器。因此,本质上,当用户点击“回复到评论”按钮时,他只需将该布尔值设置为true,并设置流生成器和回复页面上的其他小部件将使用的一些变量。