On iOS, tapping the status bar makes PrimaryScrollController go to the top:
https://flutter.dev/docs/resources/platform-adaptations#return-to-top
On iOS, tapping the OS status bar scrolls the primary scroll controller to the top position. There is no equivalent behavior on Android.
My PrimaryScrollController is attached to a ListView with reverse:true, so tapping the status bar makes it scroll to the bottom.
Docs say PrimaryScrollView handles ScrollAction if not handled by another scroll controller.
https://api.flutter.dev/flutter/widgets/PrimaryScrollController-class.html
If a ScrollAction is not handled by an otherwise focused part of the application, the ScrollAction will be evaluated using the scroll view associated with a PrimaryScrollController
How can I handle scroll actions myself so I can reverse the direction PrimaryScrollController goes when the status bar is tapped?
The easiest way to accomplish this is likely going to be reversing the items in your list instead of using the reverse: true flag of ListView.
For example:
ListView(
children: [
Container(),
Container(),
].reversed.toList(),
),
Trying to solve this any other way would get pretty involved. Since we don't have access to the StatusBar we can't override its behavior or listen for taps on it.
Related
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.
I am trying to create a workflow by which when a user presses a button, a draggable bottom sheet will appear with more controls but will still allow the user to interact with the controls in the background.
The default bottom sheet is not draggable and I also tried adding a DraggableScrollableSheet but then the background controls gets blocked.
How can I implement this workflow?
Try wrapping the bottom sheet with a gestureDetector and set its behaviour to translucent.
GestureDetector(
behavior: HitTestBehavior.translucent,
child:
)
Not sure if this works on alert or bottom sheet. Please let me know if it worked
I am trying to write a scroll pagination widget but What I am stuck some point due scroll controller. I am listening a scroll controller, if user scrolled the list to end of the listview I am sending a page request but it is not working because if first request response widgets height lesser than the view height, user can't scroll so scroll controller listener never triggering. For this problem, my question is how can I detect the scrolling is active or not ? (what I want is, if loaded page results widgets smaller than the list view height, send a new page request.)
Ruchit's answer is a good option, Or you could get the height of the widget and compare it to the screen height. That should work.
How to get the widget's height: How to get height of a Widget?
you can apply AlwaysScrollableScrollPhysics() to your gridview and it will always let the user scroll even if it has less height.
documentation: https://api.flutter.dev/flutter/widgets/AlwaysScrollableScrollPhysics-class.html
In my TabBar, there are up to 3 kinds of tabs of different widths.
"x月xx" has the widest width, "xx月" is the middle, "x月" has the narrowest width.
And when the tab state change from unselected to selected, it will become more wide because it add the prefix "xxxx年" to the title.
I can not set a specific value to tab width, because the tab title may change from "2020年11月" to "11月" if unselected.
My purpose is to center the selected tab on the screen.
The method animateTo of TabController only allows scrolling to an index but not a distance. So I copied the tabs.dart. I want to change the method _scrollToCurrentIndex() which uses a ScrollController to animate to an offset. There are many things(e.g. various TabOffsets, ScrollOffset, viewportWidth...) useful, but I still don' t know how to let scroll offset and padding work together.
I succeeded partly, that means, the selected tab will scroll to center, but the animation is strange.
In class _TabBarState extends State<TabBar> I found this in build function:
Widget tabBar = CustomPaint(
painter: _indicatorPainter,
child: _TabStyle(
// ...
child: _TabLabelBar(
onPerformLayout: _saveTabOffsets,
children: wrappedTabs,
),
),
);
In onPerformLayout: _saveTabOffsets I can get List<double> tabOffsets and double tabBarWidth. I use these to calculate the distance to scroll. But in this way, the problem is: when click a tab, it draws the indicator first, and after the indicator change from the last selected tab to the new selected tab, the tabBar scrolls to center it.
I am open to better ideas.
It's easier Listen ScrollView offset by new ScrollController more than ScrollNotification, But Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. You cannot both set primary to true and pass an explicit controller. So, Custom ScrollController broken scroll to top on iOS when tap status bar.