[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scrolling in the Drawer and NavigationDrawer triggers AppBar's scrolledUnderElevation #122600

Merged

Conversation

TahaTesser
Copy link
Member
@TahaTesser TahaTesser commented Mar 14, 2023

fixes #120083

Description

This PR fixes the unexpected scrolledUnderElevation trigger when scrolling in the Drawer and NavigationDrawer .

code sample
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(useMaterial3: true),
      home: const Example(),
    );
  }
}

class Example extends StatefulWidget {
  const Example({super.key});

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AppBar'),
      ),
      drawer: const Drawer(
        child: ListWidget(),
      ),
      body: ListView(
        children: <Widget>[
          SizedBox(
            height: 2000,
            child: Align(
              alignment: Alignment.topCenter,
              child: Text(
                'Scroll down here',
                style: Theme.of(context).textTheme.displayLarge,
                textAlign: TextAlign.center,
              ),
            ),
          )
        ],
      ),
    );
  }
}

class ListWidget extends StatefulWidget {
  const ListWidget({super.key});

  @override
  State<ListWidget> createState() => _ListWidgetState();
}

class _ListWidgetState extends State<ListWidget> {
  ScrollNotificationObserverState? _scrollNotificationObserver;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _scrollNotificationObserver?.removeListener(_listener);
    _scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context);
    _scrollNotificationObserver?.addListener(_listener);
  }

  void _listener(ScrollNotification notification) {
    print('NotificationListener: $notification');
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 30,
      itemBuilder: (BuildContext context, int index) {
        return ListTile(
          title: Text('Item $index'),
        );
      },
    );
  }
}

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard bot added f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels Mar 14, 2023
@TahaTesser TahaTesser requested a review from Piinks March 14, 2023 13:19
? (drawerTheme.shape ?? defaults.shape)
: (drawerTheme.endShape ?? defaults.endShape)),
child: child,
child: NotificationListener<Notification>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not feel right, the issue is coming from ScrollNotifications, and this feels a bit too broad.

When wrapping an the Drawer or NavigationDrawer with own NotificationListener, allowNotifications can enable notification bubbling.

This feels like a foot gun for developers, because they can then reintroduce the issue if they do not stop the notification from bubbling up themselves.

Why not just add a ScrollNotificationObserver here and return true? If folks want to listen to notifications within the drawer, they can subscribe to the observer.

Copy link
Member Author
@TahaTesser TahaTesser Mar 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I can revert the parameter. Thank you!

It only works when returning true with Notification for some reason.
This doesn't work

      child: ScrollNotificationObserver(
        child: NotificationListener<ScrollNotification>(
          onNotification: (ScrollNotification notification) {
            return true;
          },
          child: ConstrainedBox(

This does

      child: ScrollNotificationObserver(
        child: NotificationListener<Notification>(
          onNotification: (Notification notification) {
            return true;
          },
          child: ConstrainedBox(

Even tho AppBar is looking for scroll notification, this is weird.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just had to change order... fixed this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still stops any and all notifications from leaving the Drawer. I cannot think of anything in particular that would break as a result of this... but I am not sure.
@HansMuller what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose in most cases this would be safe, since the Drawer is usually part of the Scaffold, and usually nothing above the drawer cares if the Drawer is scrolling. I haven't looked at the history of this PR however it seems like it would be safer if the Scaffold squelched scroll notifications from the Drawer, rather than the Drawer doing it. It would still sort-of fail in the oddball case where there are nested scaffolds and was expected that scroll notifications from the inner Scaffold's Drawer would case the outer Scaffold to scroll. That seems like a pretty unlikely use case.

I suppose what we really need here is a way to identify the source of the notification. The AppBar only cares if the body of the Scaffold is scrolling.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose what we really need here is a way to identify the source of the notification. The AppBar only cares if the body of the Scaffold is scrolling.

Notifications could be from any nested children in the body and I don't know if there is a way to filter all notifications from the body. ScrollNotificationObserver seems to listen to all scroll notifications.

Since the app bar should not care about the scrolling notifications from the drawer.

What If we have a check like this inside the AppBar? This way we don't have squelched scroll notifications from the Drawers and AppBar can don't update MaterialState.scrolledUnder if the drawer is open. Wdyt?

  void _handleScrollNotification(ScrollNotification notification) {
    if (notification is ScrollUpdateNotification && widget.notificationPredicate(notification)) {
      final bool isAnyDrawerOpen = (notification.context?.findAncestorStateOfType<ScaffoldState>()?.isDrawerOpen ?? false)
        || (notification.context?.findAncestorStateOfType<ScaffoldState>()?.isEndDrawerOpen ?? false);
      // If any drawer is open, don't change the scrolledUnder state.
      if (!isAnyDrawerOpen) {
        final bool oldScrolledUnder = _scrolledUnder;
        final ScrollMetrics metrics = notification.metrics;
        switch (metrics.axisDirection) {
          case AxisDirection.up:
            // Scroll view is reversed
            _scrolledUnder = metrics.extentAfter > 0;
            break;
          case AxisDirection.down:
            _scrolledUnder = metrics.extentBefore > 0;
            break;
          case AxisDirection.right:
          case AxisDirection.left:
            // Scrolled under is only supported in the vertical axis, and should
            // not be altered based on horizontal notifications of the same
            // predicate since it could be a 2D scroller.
            break;
        }

        if (_scrolledUnder != oldScrolledUnder) {
          setState(() {
            // React to a change in MaterialState.scrolledUnder
          });
        }
      }
    }
  }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notifications could be from any nested children in the body and I don't know if there is a way to filter all notifications from the body. ScrollNotificationObserver seems to listen to all scroll notifications.

ScrollNotification.context.findAncestorWidgetOfExactType could be used to write a predicate that returned true if the context was a descendant of the Scaffold's body (a predicate like Scaffold.isBodyDescendant(context)).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds really good. I just updated the PR with this suggestion.

@TahaTesser TahaTesser changed the title Add allowNotifications parameter to Drawer and NavigationDrawer Fix scrolling in the Drawer and NavigationDrawer triggers AppBar's scrolledUnderElevation Mar 15, 2023
@TahaTesser TahaTesser force-pushed the fix_drawers_scrollUnderElevation branch from 6d2de20 to a14dc22 Compare March 15, 2023 14:15
@TahaTesser TahaTesser requested a review from Piinks March 15, 2023 16:20
@TahaTesser TahaTesser force-pushed the fix_drawers_scrollUnderElevation branch from a14dc22 to e731e48 Compare March 15, 2023 16:20
@TahaTesser TahaTesser requested a review from Piinks March 28, 2023 06:07
@TahaTesser TahaTesser force-pushed the fix_drawers_scrollUnderElevation branch from 404aedb to 94ab624 Compare March 29, 2023 12:53
@TahaTesser TahaTesser force-pushed the fix_drawers_scrollUnderElevation branch from 94ab624 to 5392779 Compare March 29, 2023 13:05
Copy link
Contributor
@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! LGTM!

@Piinks Piinks added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 29, 2023
@auto-submit auto-submit bot merged commit 6e04bdd into flutter:master Mar 29, 2023
@TahaTesser TahaTesser deleted the fix_drawers_scrollUnderElevation branch March 30, 2023 07:15
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2023
@Hixie
Copy link
Contributor
Hixie commented Apr 4, 2023

This apparently caused a regression: #123782

Would it make sense to revert this while the regression is being worked on?

@HansMuller
Copy link
Contributor

@TahaTesser - Since the claim in #123782 is that scrolling performance is diminished by 10% for essentially all scrolls within an app with an AppBar, then - yes - we should revert this PR and find a way to avoid the performance penalty.

TahaTesser added a commit to NevercodeHQ/flutter that referenced this pull request Apr 5, 2023
… AppBar's scrolledUnderElevation (flutter#122600)"

This reverts commit 6e04bdd.
@TahaTesser
Copy link
Member Author

@TahaTesser - Since the claim in #123782 is that scrolling performance is diminished by 10% for essentially all scrolls within an app with an AppBar, then - yes - we should revert this PR and find a way to avoid the performance penalty.

Reverting this in #124187.

Piinks added a commit that referenced this pull request Apr 5, 2023
… AppBar's scrolledUnderElevation (#122600)"

This reverts commit 6e04bdd.
exaby73 pushed a commit to NevercodeHQ/flutter that referenced this pull request Apr 17, 2023
…s scrolledUnderElevation (flutter#122600)

Fix scrolling in the  `Drawer` and `NavigationDrawer` triggers AppBar's scrolledUnderElevation
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 10, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Elevation and scrollUnderElevation depends on scrolling in NavigationDrawer
4 participants