How can i do Navigator.push in a modal bottom sheet only (not the parent page)

7,280

Solution 1

hi there i think you need navigation inside the bottomsheet as it happens in normal pages one way you can proceed is by using the below code just test out this code once i hope it will work thanks. call the openbottomsheet whenever you need to open the sheet

  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"),
        ),
      ),
    );
    }
  }

to control the back button on your parent page in which bottom sheet lies enclose the scaffold with 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()
)

try both bottomsheet and modalbottom sheet one of them provide a listener to listen the state of sheet weather it is open or closed

Solution 2

Soooo, for the benefit of anyone else who may have this same query, i have managed to do this using a modified version of Mr Azad Prajapat's answer. I am attaching the relevant code below.

Essentially, i used a stack to either show sized box of height 0 or show a container that has the stream builder, text form and other relevant widgets of the reply_to_a_comment page. Using a boolean, i am able to easily switch between what the user sees, without the entire comment page having to reload, or the user losing his current scroll position. PS: I am relatively a beginner in flutter, soo, some of the code may look too boilerplate. Just bear with me.

The new commment section code:

 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 is a boolean that tells the bottom sheet whether or not the user has tapped the "replyToAComment" button on a certain comment.

theTypeReplyThing is the widget that contains the textFormField, the emoji grid, the container for displaying the grid of selected images , the send button and the button for attaching images to a reply / comment.

showTheRepliesToTheCommentsThing is the widget that contains the replies. It is more or less the same as the comment page, except that for it, i put a small preview of the comment being replied to at the top, and i had to make the color of the container white, because it is otherwise transparent and this looks confusing.

Let me attach an image of the reply_to_a_comment page to show the difference. (i added a divider below the top bar later on. To make it look nicer) Contrast it with the image of the comment section i attached to the question. Picture of the reply to a comment page

Solution 3

There are two ways you can achieve this.

  1. If you are using modalSheet, then why do you need to use Navigator.push? Lets say, you have a comment text field/button. To the onPressed callback, you need to call showModalSheet. You don't need to routing.

    `Inkwell(child: Text("comment"),
            onTap: () => showModalSheet() //your sheet here
         ) ` 
    
  2. You can use fullScreenDailog property in MaterialPageRoute. This would suit your requirements better.

       Navigator.of(context).push(
          MaterialPageRoute(
                fullscreenDialog: true,
                builder: (context) => XYZ(),)
    
Share:
7,280
Simeon
Author by

Simeon

Updated on December 23, 2022

Comments

  • Simeon
    Simeon over 1 year

    In my app, i am trying to create a comments section. In this section, i want a user to be able to reply to another user's comment in a fashion akin to the YouTube app. I have managed to create a modal bottom sheet showing the top level comments and it is working quite well, withthe aid of several stream builders. However, the problem im facing is the second level comments (replies to people's comments.). I want to make it so that user taps on a comment and is taken to a page (still in the modal bottom sheet) where he sees all replies to the comment and can also comment on his own, and if he presses back, he goes right back to where he was and can continue scrolling through the top level comments.

    Akin to how the YouTube app looks. I had the idea of using Navigator.push inside the bottom sheet, to overlay a new page on top of the currently existing page in the modal bottom sheet and in this new page, the second level comments (replies) for a particular comment are to be displayed. But, when i call Navigator.push, the entire page changes. The whole parent page shifts to the new page, instead of just the stuff in the bottom sheet. So, that's my problem. I'm open to ideas.

    the code behind my comment bottom 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))])}))}
    

    This is what i have designed so far. The tricky bit now is making a new page in the modal sheet on press of the reply button (the message icon)

    This is what i have designed so far. The tricky bit now is making a new page in the modal sheet on press of the reply button (the message icon)

    This is what a YouTube comment system looks like. A YouTube comment system

    The code for the comment section:

    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)
                  ],
                ),
              );
            },
          ),
        );
      },
    );
    

    "the type reply thingie" is the widget that has the text input form and the send button.