In Flutter, how to disable scrolling of a child in TabBarView within NestedScrollView when its height is less than the screen?
Asked Answered
S

3

0

In Flutter, I have a TabBarView within a NestedScrollView with two children. The two children are scrollable, and are built with FutureBuilder, when there're data they return a ListView.

enter image description here

When there's no data, it'll fetch them from server, and return a Text with a notice "Nothing to show yet." before the data are loaded. However in this case, you can still scroll the blank part with only a Text even make it disappear into the top out of screen.

enter image description here

How to disable the scrolling when it's not necessary? Is it possible to make the NestedScrollView smart to decide weather to enable scroll itself, for example by comparing the children's Height and the Height of screen? Thanks!

Soteriology answered 6/9, 2020 at 15:47 Comment(2)
Attach the FutureBuilder widget code too.Wormy
My codes of the FutureBuilder are very complex. I think it is kind of irrelevant to this issue. You can think of it as a Text within a Container when there's no local data. @KedarKarkiSoteriology
A
2

You can do one thing, use NeverScrollablePhysics property when there is no data in your NestedScrollView

How?

You can check whether there is some data or not, if not, make the physics NeverScrollablePhysics else AlwaysScrollableScrollPhysics property

Code

// suppose your futurebuilder looks like this
FutureBuilder<String>(
  future: your_future, 
  builder: (BuildContext context, AsyncSnapshot<String> snapshot){
     NestedScrollView(
       // if the snapshot has some data, then scrollable else not a scrollable widget
       physics: snapshot.hasData ? AlwaysScrollableScrollPhysics() : NeverScrollableScrollPhysics()
     )
  }
)

OR

You can do one thing, use primary property inside your ListView or whatever view you are using. Do this primary: false. What it will do is to tell the widget that it is not primary and hence can only be taken into consideration when they reach to the bottom and some more data is pending to be shown.

Aleutian answered 6/9, 2020 at 16:14 Comment(2)
My structure is a lot more complex, with FutureBuilder for each child and children's children have their own FutureBuilder too. Though can't solve it simply in your way, I get your idea, thank you. Is it possible to make the NestedScrollView smart to decide weather to enable scroll itself, for example by comparing the children's Height and the Height of screen?Soteriology
I am not sure whether you can use primary in the NestedScrollView , but you can definitely use in the ListView. Use primary: false, and it will work fine @SoteriologyAleutian
S
2

I've found the key is not about scrolling, it is the SliverAppBar covering the top part of the TabBarView. A solution is to use SliverOverlapAbsorber with a SliverSafeArea, with the help from https://github.com/flutter/flutter/issues/27906#issuecomment-499043685

Sample codes:

                        SliverOverlapAbsorber(
                          handle:
                              NestedScrollView.sliverOverlapAbsorberHandleFor(
                                  context),
                          sliver: SliverSafeArea(
                            sliver: SliverAppBar(
                              floating: true,
                              pinned: true,
                              bottom: TabBar(
                                tabs: [
                                  Tab(text: "Posts"),
                                  Tab(text: "Likes"),
                                ],
                              ),
                              expandedHeight: 450,
                              flexibleSpace: FlexibleSpaceBar(
                                collapseMode: CollapseMode.pin,
                                background: Scaffold(
                                  body: Container(),
                                    ),
                                  ),
                                ),
                              ),
                            ),
Soteriology answered 7/9, 2020 at 5:2 Comment(0)
D
0

Use can do it like this You have to use SliverOverlapAbsorber in your header and

in the body of nested scroll view you have to use SliverOverlapInjector as the 1st child of your custom scrollview to absorb the scroll

Here is the sample code, like this to achieve the required behaviour

NestedScrollView(
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          SliverOverlapAbsorber(
            handle:
                NestedScrollView.sliverOverlapAbsorberHandleFor(context),
            sliver: SliverSafeArea(
              sliver: SliverAppBar(
                floating: true,
                pinned: true,
                expandedHeight: 450,
              ),
            ),
          ),
        ];
      },
      body: Builder(
        builder:(context){
         return
        CustomScrollView(slivers: [
          SliverOverlapInjector(  
            handle: 
          NestedScrollView.sliverOverlapAbsorberHandleFor(context),
          ), // this to absorb the scroll
           
          // rest of the ui 
          SliverToBoxAdapter(child: Container(
            height: 40,
            color: Colors.red
          )),
        ]);}
      )),
Disney answered 14/7 at 12:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.