SingleChildScrollView inside Row

5,745

I found a solution by wrapping the Wrap in a ConstrainedBox (instead of a row) for which the minWidth is the width of the screen.

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: const EdgeInsets.all(kPaddingMainContainer),
          child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text('Title', style: Theme.of(context).textTheme.title)
                  ],
                ),
                Padding(
                  padding: const EdgeInsets.only(top: 10),
                ),
                Expanded(
                  child: SingleChildScrollView(
                    child: ConstrainedBox(
                      constraints: BoxConstraints(
                        minWidth: MediaQuery.of(context).size.width,
                      ),
                      child: Wrap(
                        alignment: WrapAlignment.center,
                        runSpacing: 20.0, // distance between rows
                        spacing: 30.0, // distance between chips
                        children: _getWidgets(),
                      ),
                    ),
                  ),
                ),
              ]),
        ),
      ),
    );
  }

This fixed my issue and I can now scroll the Wrap widget only by tapping anywhere on the screen, while the first row with the title stays fixed.

Share:
5,745
skuallpa
Author by

skuallpa

Updated on December 12, 2022

Comments

  • skuallpa
    skuallpa over 1 year

    I have a layout made of a Column, one of its elements being a row (so that it takes the full width of the screen). Inside that row, I have a wrap, which content is pretty big and that I want to put inside a SingleChildScrollView.

    @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Container(
              padding: const EdgeInsets.all(kPaddingMainContainer),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text('Title', style: Theme.of(context).textTheme.title)
                    ],
                  ),
                  Padding(
                    padding: const EdgeInsets.only(top: 10),
                  ),
                  Row(
                    children: <Widget>[
                      Expanded(
                        child: SingleChildScrollView(
                          child: Wrap(
                            alignment: WrapAlignment.center,
                            runSpacing: 20.0, // distance between rows
                            spacing: 30.0, // distance between chips
                            children: _getWidgets(),
                          ),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        );
      }
    

    With this code, I can't get the SingleChildScrollView to make the wrap scrollable. Instead, I got a RenderFlex overflowed error.

    enter image description here

    However, if I extract the wrap from the Row, as follow:

    @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SafeArea(
            child: Container(
              padding: const EdgeInsets.all(kPaddingMainContainer),
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text('Title', style: Theme.of(context).textTheme.title)
                      ],
                    ),
                    Padding(
                      padding: const EdgeInsets.only(top: 10),
                    ),
                    Expanded(
                      child: SingleChildScrollView(
                        child: Wrap(
                          alignment: WrapAlignment.center,
                          runSpacing: 20.0, // distance between rows
                          spacing: 30.0, // distance between chips
                          children: _getWidgets(),
                        ),
                      ),
                    ),
                  ]),
            ),
          ),
        );
      }
    

    Then, the scroll is working.

    enter image description here

    However, now the wrap doesn't expand to full width anymore, what I want.

    How to use the SingleChildScrollView inside a Row ?

    PS: I don't want to wrap the Column in a SingleChildScrollView as I want my title to stay fixed and only the wrap below to scroll.

    • Andrey Turkovsky
      Andrey Turkovsky almost 5 years
      Why exactly do you need to use Row?
    • Julien Lachal
      Julien Lachal almost 5 years
      how about Slivers?
    • skuallpa
      skuallpa almost 5 years
      @AndreyTurkovsky: I experienced that if I don't put the wrap inside the row, it doesn't expand to full width, thus the user has to scroll by touching inside the area of the wrap only, what is not very user friendly. He should be able to scroll by touching anywhere on the horizontal axis (around the wrap). So that's why I wrapped it in a Row.
    • skuallpa
      skuallpa almost 5 years
      @JulienLachal: I didn't consider this option yet, I thought it should be possible with a SingleChildScrollView only. Is that the way to go?
    • Julien Lachal
      Julien Lachal almost 5 years
      AFAIK the SingleChildScrollView is useful when you want to scroll through more than the size of the screen, instead of using a ListView and be stuck when it occupies the full height of the phone. It also allows you to keep all the widgets "alive" when they appear outside of the viewport. Take a look at the Flutter video