Skip to content

Commit 73939a3

Browse files
committed
update: example
1 parent 468aa19 commit 73939a3

File tree

4 files changed

+203
-1
lines changed

4 files changed

+203
-1
lines changed

example/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ subprojects {
2626
project.evaluationDependsOn(':app')
2727
}
2828

29-
task clean(type: Delete) {
29+
tasks.register("clean", Delete) {
3030
delete rootProject.buildDir
3131
}

example/lib/features/home/home_page.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import 'package:scrollview_observer_example/features/scene/anchor_demo/anchor_wa
3131
import 'package:scrollview_observer_example/features/scene/azlist_demo/azlist_page.dart';
3232
import 'package:scrollview_observer_example/features/scene/chat_demo/page/chat_gpt_page.dart';
3333
import 'package:scrollview_observer_example/features/scene/chat_demo/page/chat_page.dart';
34+
import 'package:scrollview_observer_example/features/scene/expandable_carousel_slider_demo/expandable_carousel_slider_demo.dart';
3435
import 'package:scrollview_observer_example/features/scene/image_tab_demo/image_tab_page.dart';
3536
import 'package:scrollview_observer_example/features/scene/scrollview_form_demo/scrollview_form_demo_page.dart';
3637
import 'package:scrollview_observer_example/features/scene/video_auto_play_list/video_list_auto_play_page.dart';
@@ -282,6 +283,12 @@ class HomePage extends StatelessWidget {
282283
return const AzListPage();
283284
},
284285
),
286+
Tuple2<String, PageBuilder>(
287+
"Expandable Carousel Slider",
288+
() {
289+
return const ExpandableCarouselSliderDemo();
290+
},
291+
),
285292
];
286293
}
287294
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* @Author: LinXunFeng [email protected]
3+
* @Repo: https://github.com/fluttercandies/flutter_scrollview_observer
4+
* @Date: 2024-11-25 20:15:18
5+
*/
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter/rendering.dart';
9+
10+
import 'package:carousel_slider/carousel_slider.dart';
11+
import 'package:carousel_slider/utils.dart';
12+
import 'package:collection/collection.dart';
13+
14+
import 'package:scrollview_observer/scrollview_observer.dart';
15+
16+
class ExpandableCarouselSliderDemo extends StatefulWidget {
17+
const ExpandableCarouselSliderDemo({Key? key}) : super(key: key);
18+
19+
@override
20+
State<ExpandableCarouselSliderDemo> createState() =>
21+
_ExpandableCarouselSliderDemoState();
22+
}
23+
24+
class _ExpandableCarouselSliderDemoState
25+
extends State<ExpandableCarouselSliderDemo> {
26+
List<String> imgIdList = [
27+
'photo-1732282537685-bec9036bf4e0',
28+
'photo-1732418313819-329bc187bab7',
29+
'photo-1732135250211-5009233cee37',
30+
'photo-1731143061417-964b0768bd22',
31+
'photo-1731949594994-739b3ec954ef',
32+
'photo-1731773287304-3306a88f1e90',
33+
];
34+
List<double> itemHeightList = [500, 400, 300, 500, 400, 300];
35+
late ValueNotifier<double> carouselHeight;
36+
List<Widget> itemWidgetList = [];
37+
38+
final GlobalKey<CarouselSliderState> _carouselKey =
39+
GlobalKey<CarouselSliderState>();
40+
41+
late final observerController = ListObserverController()
42+
..observeIntervalForScrolling = const Duration(milliseconds: 1);
43+
44+
@override
45+
void initState() {
46+
super.initState();
47+
48+
carouselHeight = ValueNotifier(itemHeightList.first);
49+
itemWidgetList = imgIdList.mapIndexed((index, imgId) {
50+
return CarouselItem(
51+
index: index,
52+
height: itemHeightList[index],
53+
imgId: imgId,
54+
);
55+
}).toList();
56+
}
57+
58+
@override
59+
void dispose() {
60+
carouselHeight.dispose();
61+
super.dispose();
62+
}
63+
64+
@override
65+
Widget build(BuildContext context) {
66+
return Scaffold(
67+
appBar: AppBar(
68+
title: const Text('Expandable Carousel Slider'),
69+
),
70+
body: Column(
71+
children: [
72+
_buildCarousel(),
73+
const SizedBox(height: 20),
74+
_buildIndicator(),
75+
],
76+
),
77+
);
78+
}
79+
80+
Widget _buildIndicator() {
81+
return Container(
82+
width: 200,
83+
height: 30,
84+
alignment: Alignment.center,
85+
decoration: const BoxDecoration(
86+
color: Colors.blue,
87+
borderRadius: BorderRadius.all(Radius.circular(15)),
88+
),
89+
child: const Text(
90+
'I am an indicator',
91+
style: TextStyle(
92+
color: Colors.white,
93+
),
94+
),
95+
);
96+
}
97+
98+
Widget _buildCarousel() {
99+
Widget resultWidget = ValueListenableBuilder(
100+
valueListenable: carouselHeight,
101+
builder: (context, value, child) {
102+
return CarouselSlider(
103+
key: _carouselKey,
104+
options: CarouselOptions(
105+
viewportFraction: 1,
106+
height: carouselHeight.value,
107+
autoPlay: true,
108+
autoPlayInterval: const Duration(seconds: 4),
109+
onPageChanged: (index, reason) {},
110+
),
111+
items: itemWidgetList,
112+
);
113+
},
114+
);
115+
116+
resultWidget = ListViewObserver(
117+
controller: observerController,
118+
child: resultWidget,
119+
triggerOnObserveType: ObserverTriggerOnObserveType.directly,
120+
customTargetRenderSliverType: (renderObj) {
121+
return renderObj is RenderSliverFillViewport;
122+
},
123+
onObserve: (result) {
124+
final carouselState = _carouselKey.currentState?.carouselState;
125+
if (carouselState == null) return;
126+
if (result.displayingChildModelList.length < 2) return;
127+
128+
final firstChild = result.displayingChildModelList.first;
129+
final firstChildIndex = firstChild.index;
130+
// Get the real index of the first child.
131+
final firstChildRealIndex = getRealIndex(
132+
firstChildIndex + carouselState.initialPage,
133+
carouselState.realPage,
134+
imgIdList.length,
135+
);
136+
// Get the real index of the second child.
137+
int secondChildRealIndex = firstChildRealIndex + 1;
138+
// Reset to 0 if exceeds the range.
139+
if (secondChildRealIndex >= imgIdList.length) {
140+
secondChildRealIndex = 0;
141+
}
142+
143+
final firstChildLeadingMarginToViewport =
144+
firstChild.leadingMarginToViewport;
145+
final viewportMainAxisExtent = firstChild.viewportMainAxisExtent;
146+
final firstChildHeight = itemHeightList[firstChildRealIndex];
147+
final secondChildHeight = itemHeightList[secondChildRealIndex];
148+
149+
final progress =
150+
(firstChildLeadingMarginToViewport.abs() / viewportMainAxisExtent)
151+
.clamp(0.0, 1.0);
152+
carouselHeight.value = firstChildHeight -
153+
((firstChildHeight - secondChildHeight) * progress);
154+
},
155+
);
156+
return resultWidget;
157+
}
158+
}
159+
160+
class CarouselItem extends StatelessWidget {
161+
const CarouselItem({
162+
Key? key,
163+
required this.index,
164+
required this.height,
165+
required this.imgId,
166+
}) : super(key: key);
167+
168+
final int index;
169+
final double height;
170+
final String imgId;
171+
172+
@override
173+
Widget build(BuildContext context) {
174+
print('lxf --- ');
175+
return Stack(
176+
children: [
177+
Positioned(
178+
left: 0,
179+
right: 0,
180+
top: 0,
181+
child: Container(
182+
width: double.infinity,
183+
height: height,
184+
child: Image.network(
185+
// 'https://picsum.photos/${MediaQuery.sizeOf(context).width.toInt()}/${height.toInt()}?random=$index',
186+
'https://images.unsplash.com/$imgId?auto=format&fit=crop&w=${MediaQuery.sizeOf(context).width.toInt()}&h=${height.toInt()}&q=100',
187+
),
188+
color: index % 2 == 0 ? Colors.red : Colors.amber,
189+
),
190+
),
191+
],
192+
);
193+
}
194+
}

example/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies:
4040
easy_refresh: ^3.3.2+4
4141
visibility_detector: ^0.4.0+2
4242
flutter_sticky_header: ^0.6.5
43+
carousel_slider: ^5.0.0
4344

4445
scrollview_observer:
4546
path: ../

0 commit comments

Comments
 (0)