improve initial item scroll for list/grid
This commit is contained in:
+31
-19
@@ -187,37 +187,49 @@ class _TabGridView extends HookConsumerWidget {
|
|||||||
[screenWidth, crossAxisCount],
|
[screenWidth, crossAxisCount],
|
||||||
);
|
);
|
||||||
|
|
||||||
final lastScroll = useRef<String?>(null);
|
final didInitialScroll = useRef(false);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
|
if (didInitialScroll.value) return null;
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (scrollController.hasClients) {
|
if (scrollController.hasClients && activeTab != null) {
|
||||||
if (lastScroll.value != activeTab) {
|
final index = filteredTabEntities.value.indexWhere(
|
||||||
final index = filteredTabEntities.value.indexWhere(
|
(entity) => entity.tabId == activeTab,
|
||||||
(entity) => entity.tabId == activeTab,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
final offset = (index ~/ 2) * itemSize.height;
|
final row = index ~/ crossAxisCount;
|
||||||
|
final viewportStart = scrollController.offset;
|
||||||
|
final viewportEnd =
|
||||||
|
viewportStart + scrollController.position.viewportDimension;
|
||||||
|
final tabStart = row * itemSize.height;
|
||||||
|
final tabEnd = tabStart + itemSize.height;
|
||||||
|
|
||||||
if (offset != scrollController.offset) {
|
final isVisible =
|
||||||
lastScroll.value = activeTab;
|
tabStart >= viewportStart && tabEnd <= viewportEnd;
|
||||||
|
|
||||||
unawaited(
|
if (!isVisible) {
|
||||||
scrollController.animateTo(
|
unawaited(
|
||||||
offset,
|
scrollController.animateTo(
|
||||||
duration: const Duration(milliseconds: 200),
|
tabStart,
|
||||||
curve: Curves.easeInOut,
|
duration: const Duration(milliseconds: 200),
|
||||||
),
|
curve: Curves.easeInOut,
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
|
|
||||||
|
didInitialScroll.value = true;
|
||||||
|
} else {
|
||||||
|
didInitialScroll.value = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
didInitialScroll.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}, [filteredTabEntities, activeTab]);
|
}, [activeTab]);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
|
|||||||
+35
-19
@@ -175,37 +175,53 @@ class _TabListView extends HookConsumerWidget {
|
|||||||
|
|
||||||
final activeTab = ref.watch(selectedTabProvider);
|
final activeTab = ref.watch(selectedTabProvider);
|
||||||
|
|
||||||
final lastScroll = useRef<String?>(null);
|
final didInitialScroll = useRef(false);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
|
if (didInitialScroll.value) return null;
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (scrollController.hasClients) {
|
if (scrollController.hasClients && activeTab != null) {
|
||||||
if (lastScroll.value != activeTab) {
|
final index = filteredTabEntities.value.indexWhere(
|
||||||
final index = filteredTabEntities.value.indexWhere(
|
(entity) => entity.tabId == activeTab,
|
||||||
(entity) => entity.tabId == activeTab,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
final offset = index * _itemHeight;
|
final viewportStart = scrollController.offset;
|
||||||
|
final viewportEnd =
|
||||||
|
viewportStart + scrollController.position.viewportDimension;
|
||||||
|
final tabStart = index * _itemHeight;
|
||||||
|
final tabEnd = tabStart + _itemHeight;
|
||||||
|
|
||||||
if (offset != scrollController.offset) {
|
final isVisible =
|
||||||
lastScroll.value = activeTab;
|
tabStart >= viewportStart && tabEnd <= viewportEnd;
|
||||||
|
|
||||||
unawaited(
|
if (!isVisible) {
|
||||||
scrollController.animateTo(
|
final targetOffset = (tabStart - _itemHeight).clamp(
|
||||||
offset,
|
0.0,
|
||||||
duration: const Duration(milliseconds: 200),
|
scrollController.position.maxScrollExtent,
|
||||||
curve: Curves.easeInOut,
|
);
|
||||||
),
|
|
||||||
);
|
unawaited(
|
||||||
}
|
scrollController.animateTo(
|
||||||
|
targetOffset,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
didInitialScroll.value = true;
|
||||||
|
} else {
|
||||||
|
didInitialScroll.value = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
didInitialScroll.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}, [filteredTabEntities, activeTab]);
|
}, [activeTab]);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
|
|||||||
Reference in New Issue
Block a user