extended_nested_scroll_view
extended_nested_scroll_view copied to clipboard
[Feature Request] For outer scroller: Enable "AlwaysScrollableScrollPhysics" (or allow using any custom physics)
Hi! This is a great package already and I am grateful to you for doing all this work. I've seen many issues from you for 2 years solving this problem.
I almost have the desired behavior. If you can modify the package to allow using any custom physics or AlwaysScrollableScrollPhysics
for outer scroller, my work will be done.
Currently, even though there is a physics
parameter for NestedScrollView
, changing it doesn't work.
Expected Behavior: (For example the iOS version of the Instagram app --> go to profile screen)
-
Inner scroller should not bounce (or cannot be over scrolled) on the top edge (leading edge). When scrolling to the top of the page if the inner scroller reaches to
minScrollExtent
, it should clamp. Currently, I useClampedScrollPhysics
to stop it bounce or be over scrolled. This problem is resolved as you already said. -
The outer scroller can be over-scrolled or should bounce on the top edge if there is momentum. Like a
pull to refresh
mechanism and also I just want it to bounce instead of clamping. -
Inner scroller should bounce when reached to the bottom edge. I use my own
scroll to load more
mechanism by the way. -
The scroll friction should be lowered and the scroll detection threshold should be lowered too. This will improve the ease of use. Of course, if custom physics can be applied, I can fine-tune it by myself.
Sample video of the current situation:
Nested Scroll Physics - streamable.com - Sorry, Streamable.com deleted the videos due to prescription
Instagram example:
Instagram Profile Screen Nested Scrolling (Bounces and Can Be Over Scrolled) - Sorry, Streamable.com deleted the videos due to prescription
A Basic Reproducible Code:
import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' as extended;
class NestedWithTabs extends StatefulWidget {
@override
_NestedWithTabsState createState() => _NestedWithTabsState();
}
class _NestedWithTabsState extends State<NestedWithTabs> with TickerProviderStateMixin {
TabController tabController;
static List<String> _tabButtonTextList = ["Dogs", "Cats", "Birds"];
List<Key> _keyList = [];
static double _tabButtonHeight = 48;
static double _headerWidgetHeight = 250;
@override
void initState() {
super.initState();
tabController = TabController(
length: _tabButtonTextList.length,
initialIndex: 0,
vsync: this,
);
for (var i = 0; i < _tabButtonTextList.length; i++) {
_keyList.add(Key(_tabButtonTextList[i] + i.toString()));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: extended.NestedScrollView(
physics: AlwaysScrollableScrollPhysics(), // THIS DOES NOT WORK?
pinnedHeaderSliverHeightBuilder: () => _tabButtonHeight,
headerSliverBuilder: (BuildContext c, bool f) {
final List<Widget> widgets = <Widget>[];
widgets.add(
SliverList(
delegate: SliverChildListDelegate(
[
Container(
color: Colors.red,
height: _headerWidgetHeight,
child: Center(
child: Text("Header Widget"),
),
),
],
),
),
);
widgets.add(
SliverPersistentHeader(
pinned: true,
floating: false,
delegate: CommonSliverPersistentHeaderDelegate(
Container(
height: _tabButtonHeight,
child: TabBar(
controller: tabController,
labelColor: Colors.blue,
indicatorColor: Colors.black,
indicatorSize: TabBarIndicatorSize.label,
indicatorWeight: 2.0,
isScrollable: false,
unselectedLabelColor: Colors.grey,
tabs: _tabButtonTextList.asMap().entries.map((entry) {
return Tab(text: entry.value);
}).toList(),
),
),
_tabButtonHeight,
),
),
);
return widgets;
},
innerScrollPositionKeyBuilder: () => _keyList[tabController.index],
body: TabBarView(
controller: tabController,
children: _tabButtonTextList.asMap().entries.map((entry) {
int _thisIndex = entry.key;
return InnerScroller(
tabKey: _keyList[_thisIndex],
tabIndex: _thisIndex,
tabName: _tabButtonTextList[_thisIndex],
);
}).toList(),
),
),
);
}
}
/* -------------------------------------------------------------------------- */
/* CommonSliverPersistentHeaderDelegate */
/* -------------------------------------------------------------------------- */
class CommonSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
CommonSliverPersistentHeaderDelegate(this.child, this.height);
final Widget child;
final double height;
@override
double get minExtent => height;
@override
double get maxExtent => height;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return child;
}
@override
bool shouldRebuild(CommonSliverPersistentHeaderDelegate oldDelegate) {
//print('shouldRebuild---------------');
return oldDelegate != this;
}
}
/* -------------------------------------------------------------------------- */
/* InnerScroller */
/* -------------------------------------------------------------------------- */
class InnerScroller extends StatefulWidget {
final Key tabKey;
final int tabIndex;
final String tabName;
InnerScroller({
@required this.tabKey,
@required this.tabIndex,
@required this.tabName,
});
@override
_InnerScrollerState createState() => _InnerScrollerState();
}
class _InnerScrollerState extends State<InnerScroller> with AutomaticKeepAliveClientMixin {
static List<Color> _colorList = [Colors.indigoAccent, Colors.lime, Colors.orangeAccent];
@override
Widget build(BuildContext context) {
return extended.NestedScrollViewInnerScrollPositionKeyWidget(
widget.tabKey,
CustomScrollView(
key: PageStorageKey(widget.tabKey),
physics: ClampingScrollPhysics(),
slivers: <Widget>[
SliverGrid(
delegate: SliverChildBuilderDelegate(
(_, i) {
return Container(
margin: EdgeInsets.all(4),
height: 200,
color: _colorList[widget.tabIndex],
child: Center(
child: Text(widget.tabName + " " + i.toString()),
),
);
},
childCount: 3 * 32,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
),
],
),
);
}
@override
bool get wantKeepAlive => true;
}
Check my PR that fixed this issue: https://github.com/fluttercandies/extended_nested_scroll_view/pull/73