Skip to content

Commit 6deedb2

Browse files
committed
update: example
1 parent 42968f6 commit 6deedb2

17 files changed

+1105
-1
lines changed

example/lib/common/route/router_config.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import 'package:scrollview_observer_example/features/listview/listview_demo/list
2727
import 'package:scrollview_observer_example/features/listview/listview_dynamic_offset/listview_dynamic_offset_page.dart';
2828
import 'package:scrollview_observer_example/features/listview/listview_fixed_height_demo/listview_fixed_height_demo_page.dart';
2929
import 'package:scrollview_observer_example/features/listview/sliver_list_demo/sliver_list_demo_page.dart';
30+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_demo/nested_scrollview_demo_page.dart';
31+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/page/nested_scrollview_tab_bar_view_demo_page.dart';
3032
import 'package:scrollview_observer_example/features/pageview/pageview_demo/pageview_demo_page.dart';
3133
import 'package:scrollview_observer_example/features/pageview/pageview_demo/pageview_parallax_item_listener_page.dart';
3234
import 'package:scrollview_observer_example/features/pageview/pageview_demo/pageview_parallax_page.dart';
@@ -70,6 +72,7 @@ class MyPage {
7072
static const sliverAppBar = '/sliver_app_bar';
7173
// NestedScrollView
7274
static const nestedScrollView = '/nested_scroll_view';
75+
static const nestedScrollViewTabBarView = '/nested_scroll_view_tab_bar_view';
7376
// PageView
7477
static const pageView = '/page_view';
7578
static const pageViewParallax = '/page_view_parallax';
@@ -184,7 +187,11 @@ class MyRoute {
184187
),
185188
GoRoute(
186189
path: MyPage.nestedScrollView,
187-
builder: (context, state) => const SliverAppBarDemoPage(),
190+
builder: (context, state) => const NestedScrollViewDemoPage(),
191+
),
192+
GoRoute(
193+
path: MyPage.nestedScrollViewTabBarView,
194+
builder: (context, state) => const NestedScrollViewTabBarViewDemoPage(),
188195
),
189196
GoRoute(
190197
path: MyPage.pageView,

example/lib/features/home/home_page.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ class HomePage extends StatelessWidget {
135135
NavigationService.push(MyPage.nestedScrollView);
136136
},
137137
),
138+
ListTile(
139+
title: const Text("NestedScrollView - TabBarView"),
140+
onTap: () {
141+
NavigationService.push(MyPage.nestedScrollViewTabBarView);
142+
},
143+
),
138144
ListTile(
139145
title: const Text("PageView"),
140146
onTap: () {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* @Author: LinXunFeng linxunfeng@yeah.net
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2026-02-23 22:19:39
5+
*/
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:getx_helper/getx_helper.dart';
9+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/logic/nested_scrollview_tab_bar_view_demo_logic.dart';
10+
11+
typedef NestedScrollviewTabBarViewDemoLogicPutMixin<W extends StatefulWidget>
12+
= GetxLogicPutStateMixin<NestedScrollViewTabBarViewDemoLogic, W>;
13+
14+
typedef NestedScrollviewTabBarViewDemoLogicConsumerMixin<
15+
W extends StatefulWidget>
16+
= GetxLogicConsumerStateMixin<NestedScrollViewTabBarViewDemoLogic, W>;
17+
18+
enum NestedScrollviewTabBarViewDemoUpdateType {
19+
scrollTypeSwitch,
20+
floatingActionButton,
21+
headerSliverList,
22+
tab1View,
23+
tab2View,
24+
tab3ViewSliverList,
25+
tab3ViewSliverGrid,
26+
}
27+
28+
enum NestedScrollviewTabBarViewDemoTabType {
29+
tab1(title: "List"),
30+
tab2(title: "Grid"),
31+
tab3(title: "List+Grid");
32+
33+
const NestedScrollviewTabBarViewDemoTabType({
34+
required this.title,
35+
});
36+
37+
final String title;
38+
}
39+
40+
enum NestedScrollviewTabBarViewDemoFABClickType {
41+
headerSliverList,
42+
tab1SliverList,
43+
tab2SliverGrid,
44+
tab3SliverList,
45+
tab3SliverGrid,
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* @Author: LinXunFeng linxunfeng@yeah.net
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2026-02-23 22:19:39
5+
*/
6+
7+
import 'package:get/get.dart';
8+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/logic/nested_scrollview_tab_bar_view_demo_logic_tab_bar.dart';
9+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/state/nested_scrollview_tab_bar_view_demo_state.dart';
10+
11+
class NestedScrollViewTabBarViewDemoLogic extends GetxController
12+
with GetTickerProviderStateMixin {
13+
final NestedScrollViewTabBarViewDemoState state =
14+
NestedScrollViewTabBarViewDemoState();
15+
16+
@override
17+
void onInit() async {
18+
super.onInit();
19+
20+
onInitForTabBar();
21+
}
22+
23+
void onDispose() {
24+
onDisposeForTabBar();
25+
state.outerScrollController.dispose();
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* @Author: LinXunFeng linxunfeng@yeah.net
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2026-02-24 23:20:17
5+
*/
6+
7+
import 'package:scrollview_observer/scrollview_observer.dart';
8+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/header/nested_scrollview_tab_bar_view_demo_header.dart';
9+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/logic/nested_scrollview_tab_bar_view_demo_logic.dart';
10+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/logic/nested_scrollview_tab_bar_view_demo_logic_observer.dart';
11+
import 'package:scrollview_observer_example/utils/snackbar.dart';
12+
13+
extension NestedScrollViewTabBarViewDemoLogicForFAB
14+
on NestedScrollViewTabBarViewDemoLogic {
15+
void handleFABClick(
16+
NestedScrollviewTabBarViewDemoFABClickType type,
17+
) {
18+
final context = state.rootContext;
19+
if (context == null) return;
20+
21+
switch (type) {
22+
case NestedScrollviewTabBarViewDemoFABClickType.headerSliverList:
23+
scrollTo(
24+
position: NestedScrollUtilPosition.header,
25+
index: 1,
26+
sliverContext: state.headerSliverListCtx,
27+
);
28+
SnackBarUtil.showSnackBar(
29+
context: context,
30+
text: 'Header - SliverList - Scrolling to item 1',
31+
);
32+
break;
33+
case NestedScrollviewTabBarViewDemoFABClickType.tab1SliverList:
34+
scrollTo(
35+
position: NestedScrollUtilPosition.body,
36+
index: 1,
37+
sliverContext: state.sliverTab1ListCtx,
38+
);
39+
SnackBarUtil.showSnackBar(
40+
context: context,
41+
text: 'Body - Tab1 SliverList - Scrolling to item 1',
42+
);
43+
break;
44+
case NestedScrollviewTabBarViewDemoFABClickType.tab2SliverGrid:
45+
scrollTo(
46+
position: NestedScrollUtilPosition.body,
47+
index: 1,
48+
sliverContext: state.tab2SliverGridCtx,
49+
);
50+
SnackBarUtil.showSnackBar(
51+
context: context,
52+
text: 'Body - Tab2 SliverGrid - Scrolling to item 1',
53+
);
54+
break;
55+
case NestedScrollviewTabBarViewDemoFABClickType.tab3SliverList:
56+
scrollTo(
57+
position: NestedScrollUtilPosition.body,
58+
index: 1,
59+
sliverContext: state.tab3SliverListCtx,
60+
);
61+
SnackBarUtil.showSnackBar(
62+
context: context,
63+
text: 'Body - Tab3 SliverList - Scrolling to item 1',
64+
);
65+
66+
break;
67+
case NestedScrollviewTabBarViewDemoFABClickType.tab3SliverGrid:
68+
scrollTo(
69+
position: NestedScrollUtilPosition.body,
70+
index: 1,
71+
sliverContext: state.tab3SliverGridCtx,
72+
);
73+
SnackBarUtil.showSnackBar(
74+
context: context,
75+
text: 'Body - Tab3 SliverGrid - Scrolling to item 1',
76+
);
77+
break;
78+
}
79+
}
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* @Author: LinXunFeng linxunfeng@yeah.net
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2026-02-24 23:16:49
5+
*/
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:scrollview_observer/scrollview_observer.dart';
9+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/header/nested_scrollview_tab_bar_view_demo_header.dart';
10+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/logic/nested_scrollview_tab_bar_view_demo_logic.dart';
11+
12+
extension NestedScrollViewTabBarViewDemoLogicForObserver
13+
on NestedScrollViewTabBarViewDemoLogic {
14+
void updateNestedScrollUtilHeaderSliverContextsIfNeed({
15+
required BuildContext? oldCtx,
16+
required BuildContext newCtx,
17+
required Function() toRecordCtx,
18+
}) {
19+
if (oldCtx == newCtx) return;
20+
state.nestedScrollUtil.headerSliverContexts.remove(
21+
oldCtx,
22+
);
23+
toRecordCtx.call();
24+
state.nestedScrollUtil.headerSliverContexts.add(newCtx);
25+
}
26+
27+
void updateNestedScrollUtilBodySliverContextsIfNeed({
28+
required BuildContext? oldCtx,
29+
required BuildContext newCtx,
30+
required Function() toRecordCtx,
31+
}) {
32+
if (oldCtx == newCtx) return;
33+
state.nestedScrollUtil.bodySliverContexts.remove(
34+
oldCtx,
35+
);
36+
toRecordCtx.call();
37+
state.nestedScrollUtil.bodySliverContexts.add(newCtx);
38+
}
39+
40+
void handleOnObserveAll(Map<BuildContext, ObserveModel> resultMap) {
41+
resultMap.forEach((key, value) {
42+
// Header sliver list
43+
if (key == state.headerSliverListCtx) {
44+
final model = value as ListViewObserveModel;
45+
debugPrint("SliverListHeaderCtx: ${model.displayingChildIndexList}");
46+
if (state.hitIndexForHeaderListCtx == model.firstChild?.index) return;
47+
state.hitIndexForHeaderListCtx = model.firstChild?.index ?? 0;
48+
update([
49+
NestedScrollviewTabBarViewDemoUpdateType.headerSliverList,
50+
]);
51+
return;
52+
}
53+
54+
// Tab1 sliver list
55+
if (key == state.sliverTab1ListCtx) {
56+
final model = value as ListViewObserveModel;
57+
debugPrint("sliverTab1ListCtx: ${model.displayingChildIndexList}");
58+
if (state.hitIndexForTab1ListCtx == model.firstChild?.index) return;
59+
state.hitIndexForTab1ListCtx = model.firstChild?.index ?? 0;
60+
update([
61+
NestedScrollviewTabBarViewDemoUpdateType.tab1View,
62+
]);
63+
return;
64+
}
65+
66+
// Tab2 sliver list
67+
if (key == state.tab2SliverGridCtx) {
68+
final model = value as GridViewObserveModel;
69+
debugPrint("sliverTab2GridCtx: ${model.displayingChildIndexList}");
70+
final firstGroupChildIndexList =
71+
model.firstGroupChildList.map((e) => e.index).toList();
72+
if (state.hitIndexesForTab2Grid == firstGroupChildIndexList) return;
73+
state.hitIndexesForTab2Grid = firstGroupChildIndexList;
74+
update([
75+
NestedScrollviewTabBarViewDemoUpdateType.tab2View,
76+
]);
77+
return;
78+
}
79+
80+
// Tab2 sliver grid
81+
if (key == state.tab3SliverListCtx) {
82+
final model = value as ListViewObserveModel;
83+
debugPrint("sliverTab3ListCtx: ${model.displayingChildIndexList}");
84+
if (state.hitIndexForTab3ListCtx == model.firstChild?.index) return;
85+
state.hitIndexForTab3ListCtx = model.firstChild?.index ?? 0;
86+
update([
87+
NestedScrollviewTabBarViewDemoUpdateType.tab3ViewSliverList,
88+
]);
89+
return;
90+
}
91+
if (key == state.tab3SliverGridCtx) {
92+
final model = value as GridViewObserveModel;
93+
debugPrint("sliverTab3GridCtx: ${model.displayingChildIndexList}");
94+
final firstGroupChildIndexList =
95+
model.firstGroupChildList.map((e) => e.index).toList();
96+
if (state.hitIndexesForTab3Grid == firstGroupChildIndexList) return;
97+
state.hitIndexesForTab3Grid = firstGroupChildIndexList;
98+
update([
99+
NestedScrollviewTabBarViewDemoUpdateType.tab3ViewSliverGrid,
100+
]);
101+
return;
102+
}
103+
});
104+
}
105+
106+
void scrollTo({
107+
required NestedScrollUtilPosition position,
108+
required int index,
109+
required BuildContext? sliverContext,
110+
}) {
111+
bool isBody = NestedScrollUtilPosition.body == position;
112+
if (state.scrollToWithAnimation) {
113+
state.nestedScrollUtil.animateTo(
114+
nestedScrollViewKey: state.nestedScrollViewKey,
115+
observerController: state.observerController,
116+
position: position,
117+
index: index,
118+
duration: const Duration(milliseconds: 200),
119+
curve: Curves.easeInOut,
120+
sliverContext: sliverContext,
121+
offset: (targetOffset) {
122+
return calcPersistentHeaderExtent(
123+
targetOffset,
124+
isBody: isBody,
125+
);
126+
},
127+
);
128+
} else {
129+
state.nestedScrollUtil.jumpTo(
130+
nestedScrollViewKey: state.nestedScrollViewKey,
131+
observerController: state.observerController,
132+
position: position,
133+
index: index,
134+
sliverContext: sliverContext,
135+
offset: (targetOffset) {
136+
return calcPersistentHeaderExtent(
137+
targetOffset,
138+
isBody: isBody,
139+
);
140+
},
141+
);
142+
}
143+
}
144+
145+
double calcPersistentHeaderExtent(
146+
double offset, {
147+
required bool isBody,
148+
}) {
149+
double value = ObserverUtils.calcPersistentHeaderExtent(
150+
key: state.appBarKey,
151+
offset: offset,
152+
);
153+
if (isBody) {
154+
value += ObserverUtils.calcPersistentHeaderExtent(
155+
key: state.tabBarKey,
156+
offset: offset,
157+
);
158+
}
159+
return value;
160+
}
161+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* @Author: LinXunFeng linxunfeng@yeah.net
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2026-02-24 23:20:17
5+
*/
6+
7+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/header/nested_scrollview_tab_bar_view_demo_header.dart';
8+
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_tab_bar_view_demo/logic/nested_scrollview_tab_bar_view_demo_logic.dart';
9+
import 'package:scrollview_observer_example/utils/snackbar.dart';
10+
11+
extension NestedScrollViewTabBarViewDemoLogicForScrollTypeSwitch
12+
on NestedScrollViewTabBarViewDemoLogic {
13+
void handleScrollTypeSwitchOnChanged(bool value) async {
14+
final context = state.rootContext;
15+
if (context == null) return;
16+
17+
state.scrollToWithAnimation = value;
18+
update([
19+
NestedScrollviewTabBarViewDemoUpdateType.scrollTypeSwitch,
20+
]);
21+
SnackBarUtil.showSnackBar(
22+
context: context,
23+
text:
24+
"Animated scrolling ${state.scrollToWithAnimation ? 'Enabled' : 'Disabled'}",
25+
);
26+
}
27+
}

0 commit comments

Comments
 (0)