0

What I want to achieve is when I scroll, the appBar should expand or collapse automatically, so that there is no middle state, only collapsed or expanded completely. This feature can be seen in contact or setting app, so I want to reproduce it.

Here is my code:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class CustomAppBar extends StatelessWidget {
  final _controller = ScrollController();

  CustomAppBar({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NotificationListener<ScrollNotification>(
        onNotification: (scrollNotification) {
          if (scrollNotification is ScrollEndNotification &&
              scrollNotification.depth == 0) {
            final minExtent = scrollNotification.metrics.minScrollExtent;
            final maxExtent = scrollNotification.metrics.maxScrollExtent;
            final middle = (maxExtent - minExtent) / 2;
            final pos = scrollNotification.metrics.pixels;
            if (kDebugMode) {
              print(
                  "pos : $pos, maxExtent : $maxExtent, minExtent : $minExtent");
            }
            if (pos <= middle) {
              _controller.animateTo(minExtent,
                  duration: const Duration(milliseconds: 300),
                  curve: Curves.ease);
            } else if (middle > pos) {
              _controller.animateTo(maxExtent,
                  duration: const Duration(milliseconds: 300),
                  curve: Curves.ease);
            }
          }
          return false;
        },
        child: NestedScrollView(
          controller: _controller,
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverOverlapAbsorber(
                handle:
                    NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                sliver: const SliverAppBar(
                    expandedHeight: 200.0,
                    pinned: true,
                    flexibleSpace:
                        FlexibleSpaceBar(title: Text("Hello world"))),
              ),
            ];
          },
          body: Builder(builder: (BuildContext context) {
            return CustomScrollView(
              slivers: [
                SliverOverlapInjector(
                    handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                        context)),
                const SliverToBoxAdapter(
                    child: SizedBox(
                        height: 200, child: Center(child: Text("Slivers"))))
              ],
            );
          }),
        ),
      ),
    );
  }
}

I changed the condition and the animation but it still doesn't work as expected.

2
  • Try Flutter's SliverAppBar Commented Apr 20, 2023 at 16:04
  • Could you give an example of the solution ? 'Cause I already tried with SliverAppBar and it still doesn't make the wanted effect. Commented Apr 24, 2023 at 6:49

1 Answer 1

0

I have a work around of some sorts maybe it might help you.

  1. Create a parentScrollController and add it to the NestedScrollView.
  2. Set the scroll physics of the CustomScrollView to ClampingScrollPhysics().
  3. In the onNotification function change the condition to this -
if(
  notification is OverscrollNotification 
  && notification.overscroll < 0
) {
  parentScrollController!.jumpTo(0);
}
  1. Add an event listener to the parent scroll controller and test -
if(_scrollController.position.userScrollDirection == ScrollDirection.reverse) {
  parentScrollController!.jumpTo(
    (MediaQuery.of(context).size.height * 0.2) + kToolbarHeight
  );
}

Hope this helps. 💙

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.