Skip to content

Commit 67d9e51

Browse files
authored
Merge branch 'main' into feat/tabbar-persistent-header
2 parents 78d0cca + b82553b commit 67d9e51

1 file changed

Lines changed: 83 additions & 1 deletion

File tree

modules/ensemble/lib/layout/list_view.dart

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,21 @@ class ListView extends StatefulWidget
8888
controller.shrinkWrap = Utils.optionalBool(value),
8989
'nestedScroll': (value) =>
9090
controller.nestedScroll = Utils.optionalBool(value),
91+
'initialScrollOffset': (value) =>
92+
_controller.initialScrollOffset = Utils.optionalDouble(value),
93+
'initialScrollIndex': (value) =>
94+
_controller.initialScrollIndex = Utils.optionalInt(value),
9195
};
9296
}
9397

9498
@override
9599
Map<String, Function> methods() {
96-
return {};
100+
return {
101+
'scrollToOffset': (num offset) => _controller.scrollToOffset(offset.toDouble()),
102+
'scrollToTop': () => _controller.scrollToTop(),
103+
'scrollToBottom': () => _controller.scrollToBottom(),
104+
'scrollToIndex': (num index) => _controller.scrollToIndex(index.toInt()),
105+
};
97106
}
98107

99108
@override
@@ -127,9 +136,69 @@ class ListViewController extends BoxLayoutController {
127136
bool? shrinkWrap;
128137
bool? nestedScroll;
129138

139+
// scroll position control
140+
double? initialScrollOffset;
141+
int? initialScrollIndex;
142+
130143
void _bind(ListViewState state) {
131144
widgetState = state;
132145
}
146+
147+
/// Scroll to a specific offset
148+
void scrollToOffset(double offset, {bool animated = true}) {
149+
if (scrollController == null || !scrollController!.hasClients) return;
150+
if (animated) {
151+
scrollController!.animateTo(
152+
offset,
153+
duration: const Duration(milliseconds: 300),
154+
curve: Curves.easeInOut,
155+
);
156+
} else {
157+
scrollController!.jumpTo(offset);
158+
}
159+
}
160+
161+
/// Scroll to the top
162+
void scrollToTop({bool animated = true}) {
163+
scrollToOffset(0, animated: animated);
164+
}
165+
166+
/// Scroll to the bottom
167+
void scrollToBottom({bool animated = true}) {
168+
if (scrollController == null || !scrollController!.hasClients) return;
169+
final maxOffset = scrollController!.position.maxScrollExtent;
170+
scrollToOffset(maxOffset, animated: animated);
171+
}
172+
173+
/// Scroll to a specific item index
174+
void scrollToIndex(int index, {bool animated = true}) {
175+
if (scrollController == null || !scrollController!.hasClients) return;
176+
if (index < 0) index = 0;
177+
178+
// Get total item count from templated data
179+
final count = widgetState?.templatedDataList?.length ?? 0;
180+
if (count == 0) return;
181+
182+
// Clamp index to valid range
183+
if (index >= count) index = count - 1;
184+
185+
final maxExtent = scrollController!.position.maxScrollExtent;
186+
final viewportHeight = scrollController!.position.viewportDimension;
187+
final totalContentHeight = maxExtent + viewportHeight;
188+
189+
// Calculate estimated item height
190+
final estimatedItemHeight = totalContentHeight / count;
191+
192+
// Calculate target offset
193+
double offset = index * estimatedItemHeight;
194+
195+
// Clamp to max scroll extent
196+
if (offset > maxExtent) {
197+
offset = maxExtent;
198+
}
199+
200+
scrollToOffset(offset, animated: animated);
201+
}
133202
}
134203

135204
class ListViewState extends EWidgetState<ListView>
@@ -141,6 +210,10 @@ class ListViewState extends EWidgetState<ListView>
141210
@override
142211
void initState() {
143212
showLoading = widget._controller.showLoading;
213+
// Create scroll controller with initial offset if not already set
214+
widget._controller.scrollController ??= ScrollController(
215+
initialScrollOffset: widget._controller.initialScrollOffset ?? 0,
216+
);
144217
super.initState();
145218
}
146219

@@ -161,6 +234,15 @@ class ListViewState extends EWidgetState<ListView>
161234
});
162235
});
163236
}
237+
238+
// Handle initialScrollIndex after first frame
239+
if (widget._controller.initialScrollIndex != null) {
240+
WidgetsBinding.instance.addPostFrameCallback((_) {
241+
if (mounted) {
242+
widget._controller.scrollToIndex(widget._controller.initialScrollIndex!);
243+
}
244+
});
245+
}
164246
}
165247

166248
@override

0 commit comments

Comments
 (0)