0

Flutter's DraggableScrollableSheet Widget allows a sheet to be dragged into position and then continue scrolling the content without the user needing to start a new gesture (lift their finger from the screen).

This Widget however relies on a single scroll controller being declared which makes adding say a Navigator into that sheet with multiple scrolling pages difficult.

Instead I tried to mimic the behaviour with a Listener Widget that replaces the Draggable element and an attachable scroll listener that can modify the scroll position of any ScrollController it is attached to until the draggable sheet (Listener) updates the state to say that scrolling is now allowed.

It works perfectly but relies on overriding the ScrollController's position:

// state variable
bool allowScroll = false

if(! allowScroll){
    scrollController?.position.setPixels(0);
}

However, that may not be the most efficient way to go about it. Essentially I am overriding the ScrollPosition as apposed to ignoring gestures on the scrollable widget.

Other options such as:

  • Changing scroll physics from Never to Always
  • IgnorePointer / Absorb Pointer
  • Changing HitTestBehaviour

do not allow the same gesture to be used and require the user to lift their finger after the state change and initiate a new gesture. That would not be the correct behaviour. The above works correctly, it just feels like a hack and I wondered if there was a better approach.

Walrus
  • 19,801
  • 35
  • 121
  • 199
  • maybe overriding [this](https://api.flutter.dev/flutter/widgets/ScrollController/createScrollPosition.html) would help? – pskink Dec 06 '22 at 11:13
  • @pskink Interesting approach. Would it actually be more efficient however? – Walrus Dec 06 '22 at 11:42
  • I think so, when you create a custom `ScrollPosition` and override its `setPixels` method (i used it some time ago and i believe it is used to position the content on every scroll change) – pskink Dec 06 '22 at 11:49
  • btw of course you should extend ScrollPositionWithSingleContext, not base ScrollPosition – pskink Dec 06 '22 at 11:53
  • I tried to implement this but it still did not under the scroll position without initialising a new gesture. I also tried the hold method but encountered the same behaviour. – Walrus Dec 06 '22 at 13:57
  • did you override `setPixels` only? if so, how? – pskink Dec 06 '22 at 15:05
  • It didn't work because I applied the method for allowing it to scroll again to the scroll listener which obviously shouldn't have been firing. I well refactor. – Walrus Dec 07 '22 at 10:33
  • @pskink What if instead of settings a scroll position we use the hold function. scrollController?.position.hold(() { }); What I don't get is how to unhold it. I have called that hold inside the scrollListener so it won't be triggered again. We need to call the untold function elsewhere, but how is that done. – Walrus Dec 08 '22 at 16:27
  • I guess "unhold" is: https://api.flutter.dev/flutter/widgets/ScrollPosition/drag.html (but i never used it) – pskink Dec 08 '22 at 16:49
  • @pskink. hold(VoidCallback holdCancelCallback) → ScrollHoldController Stop the current activity and start a HoldScrollActivity. So presumably that callback can cancel the hold. What I don't see is how to trigger it outside the scrollPosition elsewhere in the code. https://api.flutter.dev/flutter/widgets/ScrollPosition/hold.html – Walrus Dec 09 '22 at 15:18

0 Answers0