Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Navigator blocks communication between CustomScrollView and NestedScrollView

Expected behaviour: The nested scroll view scrolls normaly if the custom scroll view gets scrolled and thus scrolls the appbar with it.

Actually happening: Only the custom scrollview scrolls, but not the appbar (=nested scrollview).

Wanted Behaviour can be achieved by either not using a customscrollview or not using a navigator (both no option in my case). This implementation worked before null safety if it helps in any case.

Code example:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: TestScreen(),
    );
  }
}

class TestScreen extends StatefulWidget {
  @override
  _TestScreenState createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  GlobalKey<NavigatorState> get navigatorKey =>
      GlobalKey<NavigatorState>();


  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: NestedScrollView(
          physics: BouncingScrollPhysics(),
          headerSliverBuilder: (context, innerBoxIsScrolled) => [
            SliverOverlapAbsorber(
                handle:
                    NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                sliver: SliverAppBar(
                  title: Text("title"),
                  pinned: true,
                  floating: false,
                  snap: false,
                  expandedHeight: 200,
                ))
          ],
          // body: DemoPage(),
          body: Navigator(
              key: navigatorKey,
              onGenerateRoute: (settings) =>
                  MaterialPageRoute(builder: (context) => DemoPage())),
        ));
  }
}

class DemoPage extends StatelessWidget {

  Color generateRandomColor1() {
    // Define all colors you want here
    const predefinedColors = [
      Colors.red,
      Colors.green,
      Colors.blue,
      Colors.black,
      Colors.white
    ];
    Random random = Random();
    return predefinedColors[random.nextInt(predefinedColors.length)];
  }

  @override
  Widget build(BuildContext context) {
    // return Container(
    //   color: Colors.red,
    //   height: 1000,
    //   width: 500,
    //   child: Center(
    //     child: RaisedButton(
    //       child: Text("Press"),
    //       onPressed: () {
    //         Navigator.of(context)
    //             .push(MaterialPageRoute(builder: (context) => DemoPage()));
    //       },
    //     ),
    //   ),
    // );
    return CustomScrollView(slivers: [
      SliverToBoxAdapter(
        child: Container(
          color: generateRandomColor1(),
          height: 1000,
          width: 500,
          child: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                RaisedButton(
                  child: Text("Press"),
                  onPressed: () {
                    Navigator.of(context)
                        .push(MaterialPageRoute(builder: (context) => DemoPage()));
                  },
                ),
                RaisedButton(
                  child: Text("pop"),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            ),
          ),
        ),
      )
    ]);
  }
}
like image 484
Ares Avatar asked May 25 '26 06:05

Ares


1 Answers

You can find the answer here: Answer from github

There are 2 solutions: First, get innerController of NestedScrollView and pass it by the PrimaryScrollController widget below Navigator Second, access the state of NestedScrollView from your widget where you need a controller of NestedScrollView, get innerController of NestedScrollViewState and assign that innerController to your scrollable widget P.s. You can pass controller by InheritedWidget First-way example:

...

  GlobalKey<NavigatorState> get navigatorKey =>
      GlobalKey<NavigatorState>();


  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: NestedScrollView(
          physics: BouncingScrollPhysics(),
          headerSliverBuilder: (context, innerBoxIsScrolled) => [
            SliverOverlapAbsorber(
                handle:
                    NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                sliver: SliverAppBar(
                  title: Text("title"),
                  pinned: true,
                  floating: false,
                  snap: false,
                  expandedHeight: 200,
                ))
          ],
          // body: DemoPage(),
          body: Builder(builder: (context) {
                var scrollController = PrimaryScrollController.of(context);
return Navigator(
              key: navigatorKey,
              onGenerateRoute: (settings) =>
                  MaterialPageRoute(builder: (context) => PrimaryScrollController(controller: scrollController!,
                     child: Scaffold(body:ListView(
                            children:[
                            /// children
                            ],
                             ),
                               ),
                  ))),
        );
}
        );
  }
}

The second way: You can innerController of NestedScrollView

context.findAncestorStateOfType<NestedScrollViewState>()?.innerController then pass it to your scrollable widget

CustomScrollView(
      controller: context.findAncestorStateOfType<NestedScrollViewState>()?.innerController,
      ...
      )

I think that Navigator does not pass innerController of NestedView

like image 167
Islomkhuja Akhrarov Avatar answered May 27 '26 07:05

Islomkhuja Akhrarov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!