Skip to content

added support for hiding header onListViewScroll #2041

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions modules/ensemble/lib/ensemble_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const String backgroundBluetoothSubscribeTask = 'backgroundBluetoothSubscribeTas
const String ensembleMethodChannelName = 'com.ensembleui.host.platform';
GlobalKey<NavigatorState>? externalAppNavigateKey;
ScrollController? externalScrollController;
Map<String, ScrollController> persistentControllers = {};
String? currentPageKey;

@pragma('vm:entry-point')
void callbackDispatcher() {
Expand Down
54 changes: 45 additions & 9 deletions modules/ensemble/lib/framework/view/page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class PageState extends State<Page>

@override
bool get wantKeepAlive => true;

@override
void didUpdateWidget(covariant Page oldWidget) {
super.didUpdateWidget(oldWidget);
Expand Down Expand Up @@ -196,6 +196,7 @@ class PageState extends State<Page>
@override
void didPopNext() {
super.didPopNext();
externalScrollController = ScrollController();
if (widget._pageModel.viewBehavior.onResume != null) {
ScreenController().executeActionWithScope(
context, _scopeManager, widget._pageModel.viewBehavior.onResume!,
Expand All @@ -212,6 +213,7 @@ class PageState extends State<Page>

@override
void initState() {
externalScrollController = ScrollController();
WidgetsBinding.instance.addObserver(this);
_scopeManager = ScopeManager(
widget._initialDataContext
Expand Down Expand Up @@ -253,6 +255,7 @@ class PageState extends State<Page>
// has completely rendered. This will be sufficient for most use case
widget.onRendered();
});

}

// build the root widget
Expand All @@ -270,6 +273,7 @@ class PageState extends State<Page>
// Adding a listener for [viewGroupNotifier] so we can execute
// onViewGroupUpdate when change in parent ViewGroup occurs
viewGroupNotifier.addListener(executeOnViewGroupUpdate);

}

/// This is a callback because we need the widget to be first instantiate
Expand Down Expand Up @@ -503,7 +507,9 @@ class PageState extends State<Page>
// whether to usse CustomScrollView for the entire page
bool isScrollableView =
widget._pageModel.runtimeStyles?['scrollableView'] == true;


bool collapsableHeader = widget._pageModel.runtimeStyles?['collapsableHeader'] == true;
bool collapseSafeArea = widget._pageModel.runtimeStyles?['collapseSafeArea'] == true;
PreferredSizeWidget? fixedAppBar;
if (!isScrollableView) {
fixedAppBar = buildFixedAppBar(widget._pageModel, hasDrawer);
Expand Down Expand Up @@ -544,12 +550,20 @@ class PageState extends State<Page>

// appBar is inside CustomScrollView if defined
appBar: fixedAppBar,
body: FooterLayout(
body: isScrollableView
? buildScrollablePageContent(hasDrawer)
: buildFixedPageContent(fixedAppBar != null),
footer: footerWidget,
),
body: FooterLayout(
Copy link
Member

Choose a reason for hiding this comment

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

Can you please format the code.

body: isScrollableView
? (collapsableHeader == true
? (collapseSafeArea == true
? SafeArea(
top: true,
bottom: false, // Let footer handle bottom safe area
child: buildScrollablePageContentWithCollapsableHeader(hasDrawer)
)
: buildScrollablePageContentWithCollapsableHeader(hasDrawer))
: buildScrollablePageContent(hasDrawer))
: buildFixedPageContent(fixedAppBar != null),
footer: footerWidget,
),
bottomNavigationBar: _bottomNavBar,
drawer: _drawer,
endDrawer: _endDrawer,
Expand Down Expand Up @@ -611,7 +625,7 @@ class PageState extends State<Page>
return getBody(hasAppBar);
}

Widget buildScrollablePageContent(bool hasDrawer) {
Widget buildScrollablePageContent(bool hasDrawer) {
List<Widget> slivers = [];
externalScrollController = ScrollController();
// appBar
Expand All @@ -631,6 +645,27 @@ class PageState extends State<Page>
slivers: slivers,
);
}
Widget buildScrollablePageContentWithCollapsableHeader(bool hasDrawer) {
externalScrollController = ScrollController();

return NestedScrollView(
controller: externalScrollController,
physics: ClampingScrollPhysics(),
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
List<Widget> slivers = [];
// Build the AppBar using your existing method
Widget? appBar = buildSliverAppBar(widget._pageModel, hasDrawer);

// Add AppBar to slivers if it exists and is not manually hidden
if (appBar != null) {
slivers.add(appBar);
}

return slivers;
},
body: getBody(true), // Pass true since we have a header structure
);
}

Widget getBody(bool hasAppBar) {
// ignore safe area is only applicable if we don't have an AppBar
Expand Down Expand Up @@ -994,6 +1029,7 @@ class _AnimatedAppBarState extends State<AnimatedAppBar> with WidgetsBindingObse
collapsedHeight: widget.collapsedBarHeight,
expandedHeight: widget.expandedBarHeight,
pinned: widget.pinned,
floating: widget.floating,
centerTitle: widget.centerTitle,
title: widget.animated
? switch (widget.animationType) {
Expand Down
21 changes: 15 additions & 6 deletions modules/ensemble/lib/layout/helpers/list_view_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class _ListViewCoreState extends State<ListViewCore> {
late final Debouncer debounce;
late final Debouncer _scrollDebouce;
late final ScrollController _scrollController;
double _previousOffset = 0.0;

int? _lastFetchedIndex;

Expand Down Expand Up @@ -161,16 +162,24 @@ class _ListViewCoreState extends State<ListViewCore> {
// given the nestedScroll property is set to true and View is Scrollable
// Note that we are not using jumpTo to avoid jerky movement of external
// Scroll instead we are using animateTo which is smoother than jumpTo
ScrollController? currentExternalScrollController = externalScrollController;
if (externalScrollController != null &&
widget.nestedScroll &&
widget.shrinkWrap) {
final currentOffset = _scrollController.position.pixels;
_scrollController.addListener(() {

final currentOffset = _scrollController.offset;
final scrollingUp = currentOffset > _previousOffset;
final scrollingDown = currentOffset < _previousOffset;

if (scrollingUp) {
currentExternalScrollController!.animateTo(100, duration: const Duration(milliseconds: 16), curve: Curves.linear);
Copy link
Member

Choose a reason for hiding this comment

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

Please use the values from animation map and then have these as default values if not given.

} else if (scrollingDown && currentOffset > 0) {
currentExternalScrollController!.jumpTo(0);
}

externalScrollController!.animateTo(
currentOffset,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
_previousOffset = currentOffset;
});
}
}

Expand Down