Skip to content

Can't scroll through whole viewport using ScrollBar. #111968

Closed

Description

@knopp

Run the example below and keep scrolling using the scrollbar from beginning to end multiple times. Eventually you should stop seeing the red lines at the beginning and end.

This is a regression after #111250 . I think this is caused by multiple factors though. Viewport dimensions in flutter tend to change depending on current scroll position and sliver layout and often is just an approximation. Scroll offset during scrollbar dragging is adjusted relatively after each movement which compounds the error. Eventually this causes problem at the scroll boundaries.

I think possible solution would be to force position.minScrollExtent and position.maxScrollExtent at scrollbar boundaries. With the complication of position.maxScrollExtent being an approximation that might change once actually scrolled to end.

Perhaps the end position could be determined through several layout iterations (if the viewport dimensions keep changing).

cc @TahaTesser

flutter pub add flutter_lorem
import 'package:flutter/material.dart';
import 'package:flutter_lorem/flutter_lorem.dart';

void main() {
  runApp(const MaterialApp(
    title: 'Flutter Demo',
    home: MyHomePage(),
  ));
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late List<String> items;

  @override
  void initState() {
    super.initState();
    items = List<String>.generate(
        100, (i) => lorem(paragraphs: 1, words: Object.hash(i, null) % 100));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(
            child: Container(
              height: 2,
              color: Colors.red,
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => Padding(
                padding: const EdgeInsets.all(20),
                child: Text(items[index]),
              ),
              childCount: items.length,
            ),
          ),
          SliverToBoxAdapter(
            child: Container(
              height: 2,
              color: Colors.red,
            ),
          ),
        ],
      ),
    );
  }
}

Activity

  1. TahaTesser commented on Sep 20, 2022

    @TahaTesser
    Contributor

    I'm Investigating this.

    cc: @Piinks

  2. added
    c: regressionIt was better in the past than it is now
    frameworkflutter/packages/flutter repository. See also f: labels.
    f: scrollingViewports, list views, slivers, etc.
    on Sep 20, 2022
  3. Piinks commented on Sep 20, 2022

    @Piinks
    Contributor

    Hmm, especially since this just landed, we should revert it. That way we can investigate and fix it thoroughly, rather than trying to do so quickly while this regression exists. I am staging a revert now.

  4. self-assigned this
    on Sep 20, 2022
  5. moved this to To do in Nevercodeon Sep 20, 2022
  6. TahaTesser commented on Sep 20, 2022

    @TahaTesser
    Contributor

    @Piinks
    Agreed! I will investigate more and hopefully reland with regression tests

  7. removed their assignment
    on Sep 20, 2022
  8. knopp commented on Sep 20, 2022

    @knopp
    MemberAuthor

    I think the original PR was not necessarily wrong. This just points to a deeper problem with how scrollbar interacts with scroll position. You shouldn't need to overdrag a scrollbar in order to get to actual viewport boundaries.

  9. TahaTesser commented on Sep 20, 2022

    @TahaTesser
    Contributor

    You shouldn't need to overdrag a scrollbar in order to get to actual viewport boundaries.

    Exactly. I did some initial testing with the code sample you provided and compared it to the App Store app scrollbar. Scrollbar reached down without over-drag.

  10. Piinks commented on Sep 20, 2022

    @Piinks
    Contributor

    I think in this case, the maxScrollExtent is not precise because unless there are fixed, predetermined metrics, the scroll view will estimate the max extent.

    Here is some more context:

    In cases where Flutter can't determine the exact max extent ahead of time, you may want to allow overdrag. Or, what may be needed here is edge scrolling, like with text selection. Where dragging the scrollbar to the end but there is still more extent to reveal, holding the pointer there at the end will animate the scroll view further forward.. Not sure which is best, I will leave that up to @TahaTesser to explore. :)

  11. knopp commented on Sep 20, 2022

    @knopp
    MemberAuthor

    I suggested some of possible options in original comment.

    I think the minScrollExtent should be more or less always correct. So when the scrollbar is at top position it should always be at minScrollExtent, regardless of possible error accumulated on the way.

    maxScrollExtent is trickier, since you can know for sure what it is only when trailing children are materialized. That's where I suggested possible iterative approach, i.e. when reaching end set the scroll position to max scroll extent multiple times in a row. This may take multiple layout passes to settle, perhaps even multiple frames, but it would still be better than relying on manually overdraging the scrollview.

    I think no matter how good the estimation is, there are still going to be corner cases.

  12. knopp commented on Sep 20, 2022

    @knopp
    MemberAuthor

    Also to consider - we have a custom version of SliverList, that supports variable item extents with very long lists. This is currently not doable with flutter SliverList because to jump at any offset it needs to materialize and layout all items before.

    We instead esitmate target index from scroll offset and then generate items in cached area. When scrolling up the scroll offset is periodically adjusted to account of error in our estimation vs actual item height. It works very well, but in some cases confuses Flutter scrollbars even more than regular SliverList :)

  13. TahaTesser commented on Sep 20, 2022

    @TahaTesser
    Contributor

    cc: @Piinks @knopp
    This helps a lot! I'm looking forward to figuring this out.

  14. Piinks commented on Sep 20, 2022

    @Piinks
    Contributor

    This may take multiple layout passes to settle, perhaps even multiple frames

    This sounds like it would be very expensive and potentially have performance issues. Layout in flutter is single pass in order to maintain fast and efficient performance.

  15. knopp commented on Sep 20, 2022

    @knopp
    MemberAuthor

    This may take multiple layout passes to settle, perhaps even multiple frames

    This sounds like it would be very expensive and potentially have performance issues. Layout in flutter is single pass in order to maintain fast and efficient performance.

    There can be possibly multiple passes in sliver layout when correcting scroll offset, though those are usually not complete passes.

    I meant more something like scheduling additional frame with new offset while user is pressing down at the end of scrollbar, i.e. something that user would do when overdragging, just automatically. But I understand how that might be bit questionable.

  16. knopp commented on Sep 21, 2022

    @knopp
    MemberAuthor

    Other possible option would be hint in SliverConstraint that scrolling is at the end, in which case SliverList may be able to correct scroll offset to actually reach the very end of content.

  17. github-actions commented on Oct 5, 2022

    @github-actions

    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.

  18. locked as resolved and limited conversation to collaborators on Oct 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: regressionIt was better in the past than it is nowf: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions