flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond

Home Page:https://flutter.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NestedScrollView : is there any way to support multiple child for SliverOverlapAbsorber

zmtzawqlp opened this issue · comments

As [flutter document(https://docs.flutter.io/flutter/widgets/NestedScrollView-class.html) said about SliverOverlapAbsorber
// This widget takes the overlapping behavior of the SliverAppBar,
// and redirects it to the SliverOverlapInjector below. If it is
// missing, then it is possible for the nested "inner" scroll view
// below to end up under the SliverAppBar even when the inner
// scroll view thinks it has not been scrolled.
// This is not necessary if the "headerSliverBuilder" only builds
// widgets that do not overlap the next sliver.

SliverOverlapAbsorber can fix the Scroll postion in body scroll widget. is there any way to support
multiple child. as i use a pinned SliverPersistentHeader under a SliverOverlapAbsorber
more info please see the gif and demo code. thanks

373096261108bffd940561f8af23535c
main6.zip

i have done some things to solve this thing, may be you have better solution 。please check it when you have the time.
i notice outerscrollcontrol will handle the pinned scroll extend, so i done some to fix it.
https://github.com/fluttercandies/extended_nested_scroll_view

Any progress on this issue? This should be fixed in the flutter itself as well

It’s already in the second half of 2019, and I still haven’t seen any progress on this issue. T_T

commented

@vanlooverenkoen I don't understand why this ticket was closed. This ticket is definitely not addressed as of today.
Flutter provides no solution to absorb the height of more than one child. This limits design abilities as no fixed size element can be used between the AppBar and the scrolling content of a child.

I am still having this issue, it is not yet resolved from flutter

My approach: use MultiSliver widget from sliver_tools 0.1.8 to wrap the multiple slivers within SliverOverlapAbsorber. Any other possible approaches at the moment?

Still facing this issue, any updates?

I am also facing this issue. @zoechi is there any update on this issue?

me too

any updates?

I'm facing the same issue.

I'm still facing this issue

I have not tried this yet, but it occurred to me this morning that the sliver_tools package may resolve this. You could use the sliver group - MultiSliver I think - to group more one sliver together and then wrap it in the the SliverOverlapAbsorber.

sliver_tools

totally works many thanks

@Piinks the sliver_tools is a workaround right? This should still be fixed in flutter itself as well?

I'm also facing this issue.
Also If I put another sliver above SliverOverlapAbsorber, it works fine but the scrolling speed becomes inconsistent when body starts to scroll.
Hope to see updates.

@Piinks the sliver_tools is a workaround right? This should still be fixed in flutter itself as well?

Hey @vanlooverenkoen I am not sure! At this time there is no one actively working on this, but the issue remains open. :)

This feature would be really helpful!

MultiSliverOverlapAbsorber is a bad solution because I need another sliver between two (or more) SliverAppBars. The best solution is to allow several SliverOverlapAbsorbers with a single handle.

Also need this feature

It will be great to have this feature!

hello, one solution is to use a SliverOverlapAbsorber with pinned = true
like here: https://api.flutter.dev/flutter/widgets/NestedScrollView-class.html

@popalexandru Could you add an example of how it would look like. Was just refactoring code on one project I recently joined and it had SliverOverlapAbsorber, which, unfortunately, didn't help with the discussed issue.

hello, one solution is to use a SliverOverlapAbsorber with pinned = true like here: https://api.flutter.dev/flutter/widgets/NestedScrollView-class.html

These example seem it work but ListView inside each tab will affect for all tab when you scroll one of them.

Using MultiSliver worked out fine for me.

SliverOverlapAbsorber(
    handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
    sliver: MultiSliver(
      pushPinnedChildren: false, // defaults to false
      children: <Widget>[
        SliverPersistentHeader(
          pinned: true,
          floating: false,
          delegate: AppbarDelegateWidget(),
        ),
        SliverAppBar(
          elevation: 0,
          automaticallyImplyLeading: false,
          backgroundColor: Theme.defaultColorBg,
          pinned: false,
          floating: false,
          snap: false,
          expandedHeight: 200,
          forceElevated: innerBoxIsScrolled,
          flexibleSpace: FlexibleSpaceBar(
            background: Container(
              color: Theme.defaultColorBg,
              width: MediaQuery.of(context).size.width,
              child: DashBoardGraph(),
            ),
          ),
        ),
        SliverPersistentHeader(
          pinned: true,
          floating: false,
          delegate: DashboardTabBarDelegate(onTap: (int index) {
            injector<DashboardViewModel>().jumpToTopOfPage();
          }),
        ),
      ],
    ),
  ),

Additionally, you might want to wrap the body with a SliverSafeArea or top padding.

Using MultiSliver worked out fine for me.

SliverOverlapAbsorber(
    handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
    sliver: MultiSliver(
      pushPinnedChildren: false, // defaults to false
      children: <Widget>[
        SliverPersistentHeader(
          pinned: true,
          floating: false,
          delegate: AppbarDelegateWidget(),
        ),
        SliverAppBar(
          elevation: 0,
          automaticallyImplyLeading: false,
          backgroundColor: Theme.defaultColorBg,
          pinned: false,
          floating: false,
          snap: false,
          expandedHeight: 200,
          forceElevated: innerBoxIsScrolled,
          flexibleSpace: FlexibleSpaceBar(
            background: Container(
              color: Theme.defaultColorBg,
              width: MediaQuery.of(context).size.width,
              child: DashBoardGraph(),
            ),
          ),
        ),
        SliverPersistentHeader(
          pinned: true,
          floating: false,
          delegate: DashboardTabBarDelegate(onTap: (int index) {
            injector<DashboardViewModel>().jumpToTopOfPage();
          }),
        ),
      ],
    ),
  ),

Additionally, you might want to wrap the body with a SliverSafeArea or top padding.

Not working when using multiple SliverAppBar pinned with flexibleSpaceBar.

This code support double sliver pinned appbar without the issue where small body go behind second app bar.

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Home(),
    ),
  );
}

class Home extends StatelessWidget {
  Home({super.key});

  final SliverOverlapAbsorberHandle appBar = SliverOverlapAbsorberHandle();
  final SliverOverlapAbsorberHandle disconnectBar =
      SliverOverlapAbsorberHandle();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: NestedScrollView(
        physics: const ClampingScrollPhysics(),
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) =>
            <Widget>[
          SliverOverlapAbsorber(
            handle: appBar,
            sliver: const SliverAppBar(
              pinned: true,
              backgroundColor: Colors.red,
              elevation: 0,
              toolbarHeight: 50,
              expandedHeight: 100,
              title: Center(
                child: Text("First pinned appbar"),
              ),
            ),
          ),
          SliverOverlapAbsorber(
            handle: disconnectBar,
            sliver: const SliverAppBar(
              pinned: true,
              backgroundColor: Colors.green,
              elevation: 0,
              primary: false,
              toolbarHeight: 20,
              expandedHeight: 100,
              title: Center(
                child: Text("Second pinned appbar"),
              ),
            ),
          ),
        ],
        body: Builder(
          builder: (BuildContext context) => CustomScrollView(
            slivers: <Widget>[
              SliverOverlapInjector(handle: appBar),
              SliverOverlapInjector(handle: disconnectBar),
              SliverToBoxAdapter(
                child: Container(
                  color: Colors.grey,
                  height: 100,
                  width: double.infinity,
                  child: const Center(child: Text("body")),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

untitled

This code support double sliver pinned appbar without the issue where small body go behind second app bar.

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Home(),
    ),
  );
}

class Home extends StatelessWidget {
  Home({super.key});

  final SliverOverlapAbsorberHandle appBar = SliverOverlapAbsorberHandle();
  final SliverOverlapAbsorberHandle disconnectBar =
      SliverOverlapAbsorberHandle();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: NestedScrollView(
        physics: const ClampingScrollPhysics(),
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) =>
            <Widget>[
          SliverOverlapAbsorber(
            handle: appBar,
            sliver: const SliverAppBar(
              pinned: true,
              backgroundColor: Colors.red,
              elevation: 0,
              toolbarHeight: 50,
              expandedHeight: 100,
              title: Center(
                child: Text("First pinned appbar"),
              ),
            ),
          ),
          SliverOverlapAbsorber(
            handle: disconnectBar,
            sliver: const SliverAppBar(
              pinned: true,
              backgroundColor: Colors.green,
              elevation: 0,
              primary: false,
              toolbarHeight: 20,
              expandedHeight: 100,
              title: Center(
                child: Text("Second pinned appbar"),
              ),
            ),
          ),
        ],
        body: Builder(
          builder: (BuildContext context) => CustomScrollView(
            slivers: <Widget>[
              SliverOverlapInjector(handle: appBar),
              SliverOverlapInjector(handle: disconnectBar),
              SliverToBoxAdapter(
                child: Container(
                  color: Colors.grey,
                  height: 100,
                  width: double.infinity,
                  child: const Center(child: Text("body")),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

untitled untitled

worked out fine for me!! thanks!!

#22393 (comment)

The solution presented here doesn't work properly when you have a CustomScrollView in the body of your NestedScrollView, only the MultiSliver seems to do the work.

#22393 (comment)

It works for my case.
headerSliverBuilder of NestedScrollView has one floating appbar, one pinned appbar

and body has CustomScrollview, it has 2 SliverOverlapInjector.

It works properly even with CustomScrollView in the body of NestedScrollView

Resolving #33137 (currently in progress) will resolve this as well since multiple slivers will be able to go into the group, and the group itself will be able to go into the SliverOverlapAbsorber. 👍

This has been resolved by #126596. With SliverMainAxisGroup, multiple slivers can be wrapped by the group, and then the group can be provided to the SliverOverlapAbsorber. :) cc @thkim1011

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.