Skip to content

Commit 458d837

Browse files
committed
update: example
1 parent 83256cb commit 458d837

File tree

3 files changed

+295
-26
lines changed

3 files changed

+295
-26
lines changed

example/lib/features/home/home_page.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import 'package:scrollview_observer_example/features/listview/listview_fixed_hei
2424
import 'package:scrollview_observer_example/features/listview/sliver_list_demo/sliver_list_demo_page.dart';
2525
import 'package:scrollview_observer_example/features/nested_scrollview/nested_scrollview_demo/nested_scrollview_demo_page.dart';
2626
import 'package:scrollview_observer_example/features/pageview/pageview_demo/pageview_demo_page.dart';
27+
import 'package:scrollview_observer_example/features/pageview/pageview_demo/pageview_parallax_page.dart';
2728
import 'package:scrollview_observer_example/features/scene/anchor_demo/anchor_page.dart';
2829
import 'package:scrollview_observer_example/features/scene/anchor_demo/anchor_waterfall_page.dart';
2930
import 'package:scrollview_observer_example/features/scene/azlist_demo/azlist_page.dart';
@@ -196,6 +197,12 @@ class HomePage extends StatelessWidget {
196197
return const PageViewDemoPage();
197198
},
198199
),
200+
Tuple2<String, PageBuilder>(
201+
"PageView - Parallax",
202+
() {
203+
return const PageViewParallaxPage();
204+
},
205+
),
199206
Tuple2<String, PageBuilder>(
200207
"VideoList AutoPlay",
201208
() {

example/lib/features/pageview/pageview_demo/pageview_demo_page.dart

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,23 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
2020

2121
late PageController pageController;
2222

23-
int pageItemCount = 10;
23+
List<String> pageItemBgPicList = [
24+
'11898897',
25+
'26653530',
26+
'12974784',
27+
'943459',
28+
'4424178',
29+
'20433037',
30+
'4424137',
31+
'4955810',
32+
'4424137',
33+
'18847956',
34+
]
35+
.map((id) =>
36+
'https://images.pexels.com/photos/$id/pexels-photo-$id.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2')
37+
.toList();
38+
39+
int get pageItemCount => pageItemBgPicList.length;
2440

2541
List<ValueNotifier<double>> pageItemOffsetYList = [];
2642

@@ -31,7 +47,7 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
3147
super.initState();
3248
pageController = PageController(
3349
initialPage: 4,
34-
viewportFraction: 0.9,
50+
viewportFraction: 0.8,
3551
);
3652
pageItemOffsetYList = List.generate(
3753
pageItemCount,
@@ -55,7 +71,22 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
5571
Widget build(BuildContext context) {
5672
return Scaffold(
5773
appBar: AppBar(
58-
title: const Text("PageView"),
74+
title: const Text(
75+
"PageView",
76+
style: TextStyle(
77+
color: Colors.white,
78+
),
79+
),
80+
backgroundColor: Colors.black87,
81+
leading: IconButton(
82+
icon: const Icon(
83+
Icons.arrow_back_ios_new,
84+
color: Colors.white,
85+
),
86+
onPressed: () {
87+
Navigator.of(context).pop();
88+
},
89+
),
5990
),
6091
body: Stack(
6192
children: [
@@ -76,7 +107,7 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
76107
width: 500,
77108
height: 900,
78109
child: Image.network(
79-
'https://img2.baidu.com/it/u=675935710,2689018786&fm=253&fmt=auto&app=138&f=JPG?w=1061&h=500',
110+
'https://images.pexels.com/photos/41949/earth-earth-at-night-night-lights-41949.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2',
80111
fit: BoxFit.fitHeight,
81112
),
82113
);
@@ -101,28 +132,7 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
101132
Widget resultWidget = PageView.builder(
102133
controller: pageController,
103134
itemBuilder: (context, index) {
104-
Widget itemWidget = Container(
105-
decoration: BoxDecoration(
106-
color: Colors.blue[100],
107-
borderRadius: BorderRadius.circular(4),
108-
),
109-
alignment: Alignment.center,
110-
child: Text("Page $index"),
111-
);
112-
Widget resultWidget = ValueListenableBuilder(
113-
valueListenable: pageItemOffsetYList[index],
114-
builder: (BuildContext context, double offsetY, Widget? child) {
115-
return Transform.translate(
116-
offset: Offset(0, offsetY),
117-
child: itemWidget,
118-
);
119-
},
120-
);
121-
resultWidget = Container(
122-
margin: const EdgeInsets.symmetric(horizontal: 8),
123-
child: resultWidget,
124-
);
125-
return resultWidget;
135+
return _buildPageItem(index);
126136
},
127137
itemCount: pageItemCount,
128138
);
@@ -135,6 +145,8 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
135145
for (var itemModel in displayingChildModelList) {
136146
final itemIndex = itemModel.index;
137147
final itemDisplayPercentage = itemModel.displayPercentage;
148+
149+
// Calculates pageItemOffsetY
138150
final offsetY = (1 - itemDisplayPercentage) * offsetYDelta;
139151
pageItemOffsetYList[itemIndex].value = offsetY;
140152
}
@@ -149,4 +161,57 @@ class _PageViewDemoPageState extends State<PageViewDemoPage> {
149161
);
150162
return resultWidget;
151163
}
164+
165+
Widget _buildPageItem(int index) {
166+
Widget itemWidget = Container(
167+
decoration: BoxDecoration(
168+
color: Colors.blue[100],
169+
borderRadius: BorderRadius.circular(4),
170+
),
171+
clipBehavior: Clip.antiAlias,
172+
alignment: Alignment.center,
173+
child: Stack(
174+
children: [
175+
Positioned(
176+
left: 0,
177+
right: 0,
178+
top: 0,
179+
bottom: 0,
180+
child: _buildPageItemBgPicView(index),
181+
),
182+
const SizedBox.expand(),
183+
Container(
184+
width: double.infinity,
185+
alignment: Alignment.center,
186+
height: 44,
187+
decoration: const BoxDecoration(
188+
color: Colors.white54,
189+
),
190+
child: Text("Page $index"),
191+
),
192+
],
193+
),
194+
);
195+
Widget resultWidget = ValueListenableBuilder(
196+
valueListenable: pageItemOffsetYList[index],
197+
builder: (BuildContext context, double offsetY, Widget? child) {
198+
return Transform.translate(
199+
offset: Offset(0, offsetY),
200+
child: itemWidget,
201+
);
202+
},
203+
);
204+
resultWidget = Container(
205+
margin: const EdgeInsets.symmetric(horizontal: 8),
206+
child: resultWidget,
207+
);
208+
return resultWidget;
209+
}
210+
211+
Widget _buildPageItemBgPicView(int index) {
212+
return Image.network(
213+
pageItemBgPicList[index],
214+
fit: BoxFit.cover,
215+
);
216+
}
152217
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* @Author: LinXunFeng [email protected]
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2024-08-26 21:30:59
5+
*/
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter/rendering.dart';
9+
import 'package:scrollview_observer/scrollview_observer.dart';
10+
11+
class PageViewParallaxPage extends StatefulWidget {
12+
const PageViewParallaxPage({Key? key}) : super(key: key);
13+
14+
@override
15+
State<PageViewParallaxPage> createState() => _PageViewParallaxPageState();
16+
}
17+
18+
class _PageViewParallaxPageState extends State<PageViewParallaxPage> {
19+
late PageController pageController;
20+
21+
List<String> pageItemBgPicList = [
22+
'11898897',
23+
'26653530',
24+
'12974784',
25+
'943459',
26+
'4424178',
27+
'20433037',
28+
'4424137',
29+
'4955810',
30+
'4424137',
31+
'18847956',
32+
]
33+
.map((id) =>
34+
'https://images.pexels.com/photos/$id/pexels-photo-$id.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2')
35+
.toList();
36+
37+
int get pageItemCount => pageItemBgPicList.length;
38+
39+
List<ValueNotifier<double>> pageItemBgPicAlignmentXList = [];
40+
41+
final observerController = ListObserverController();
42+
43+
@override
44+
void initState() {
45+
super.initState();
46+
pageController = PageController(
47+
initialPage: 4,
48+
viewportFraction: 0.9,
49+
);
50+
pageItemBgPicAlignmentXList = List.generate(
51+
pageItemCount,
52+
(index) {
53+
return ValueNotifier<double>(0);
54+
},
55+
);
56+
57+
Future.delayed(const Duration(milliseconds: 100)).then((_) {
58+
observerController.dispatchOnceObserve();
59+
});
60+
}
61+
62+
@override
63+
void dispose() {
64+
pageController.dispose();
65+
super.dispose();
66+
}
67+
68+
@override
69+
Widget build(BuildContext context) {
70+
return Scaffold(
71+
backgroundColor: Colors.amber[50],
72+
appBar: AppBar(
73+
title: const Text(
74+
"PageView - Parallax",
75+
style: TextStyle(
76+
color: Colors.white,
77+
),
78+
),
79+
backgroundColor: Colors.black87,
80+
leading: IconButton(
81+
icon: const Icon(
82+
Icons.arrow_back_ios_new,
83+
color: Colors.white,
84+
),
85+
onPressed: () {
86+
Navigator.of(context).pop();
87+
},
88+
),
89+
),
90+
body: Center(
91+
child: _buildPageView(),
92+
),
93+
);
94+
}
95+
96+
Widget _buildPageView() {
97+
Widget resultWidget = PageView.builder(
98+
controller: pageController,
99+
itemBuilder: (context, index) {
100+
return _buildPageItem(index);
101+
},
102+
itemCount: pageItemCount,
103+
);
104+
resultWidget = ListViewObserver(
105+
controller: observerController,
106+
child: resultWidget,
107+
triggerOnObserveType: ObserverTriggerOnObserveType.directly,
108+
onObserve: (resultModel) {
109+
final displayingChildModelList = resultModel.displayingChildModelList;
110+
for (var itemModel in displayingChildModelList) {
111+
final itemIndex = itemModel.index;
112+
final itemDisplayPercentage = itemModel.displayPercentage;
113+
114+
// Calculates itemAlignmentX
115+
double itemAlignmentX = 1 - itemDisplayPercentage;
116+
if (itemModel.leadingMarginToViewport > 0) {
117+
itemAlignmentX = -itemAlignmentX;
118+
}
119+
if (itemAlignmentX > 1) {
120+
itemAlignmentX = 1;
121+
} else if (itemAlignmentX < -1) {
122+
itemAlignmentX = -1;
123+
}
124+
pageItemBgPicAlignmentXList[itemIndex].value = itemAlignmentX;
125+
}
126+
},
127+
customTargetRenderSliverType: (renderObj) {
128+
return renderObj is RenderSliverFillViewport;
129+
},
130+
);
131+
132+
resultWidget = SizedBox(
133+
height: (MediaQuery.sizeOf(context).height -
134+
MediaQuery.paddingOf(context).top -
135+
kToolbarHeight) *
136+
0.8,
137+
child: resultWidget,
138+
);
139+
return resultWidget;
140+
}
141+
142+
Widget _buildPageItem(int index) {
143+
Widget resultWidget = Container(
144+
decoration: BoxDecoration(
145+
color: Colors.blue[50],
146+
borderRadius: BorderRadius.circular(10),
147+
),
148+
clipBehavior: Clip.antiAlias,
149+
alignment: Alignment.center,
150+
child: Stack(
151+
alignment: AlignmentDirectional.center,
152+
children: [
153+
Positioned(
154+
left: 0,
155+
right: 0,
156+
top: 0,
157+
bottom: 0,
158+
child: _buildPageItemBgPicView(index),
159+
),
160+
const SizedBox.expand(),
161+
_buildNum(index),
162+
],
163+
),
164+
);
165+
resultWidget = Container(
166+
margin: const EdgeInsets.symmetric(horizontal: 8),
167+
child: resultWidget,
168+
);
169+
return resultWidget;
170+
}
171+
172+
Widget _buildNum(int index) {
173+
return Container(
174+
alignment: Alignment.center,
175+
width: 80,
176+
height: 80,
177+
decoration: BoxDecoration(
178+
color: Colors.white.withOpacity(0.8),
179+
borderRadius: BorderRadius.circular(10),
180+
),
181+
child: Text("Page $index"),
182+
);
183+
}
184+
185+
Widget _buildPageItemBgPicView(int index) {
186+
return ValueListenableBuilder(
187+
valueListenable: pageItemBgPicAlignmentXList[index],
188+
builder: (BuildContext context, double alignmentX, Widget? child) {
189+
return Image.network(
190+
pageItemBgPicList[index],
191+
fit: BoxFit.cover,
192+
alignment: Alignment(alignmentX, 0),
193+
);
194+
},
195+
);
196+
}
197+
}

0 commit comments

Comments
 (0)