Flutter 精准滚动
2025-11-10 本文已影响0人
河马过河
// 滚动到当前播放行(优化版:直接使用精确高度计算)
void _scrollToCurrentLine() {
if(!logic.isAudioPlaying.value) return;
_isEditLineIndex = -1;
// 音频播放时关闭键盘
_transcriptFocusNode.unfocus();
String lrcContent = logic.note?.lrcDescription ?? "";
if (lrcContent.isEmpty) return;
List<LrcLine> lrcLines = _getCachedLrcLines(lrcContent);
if (lrcLines.isEmpty) return;
int currentLineIndex = _getCurrentLineIndex(lrcLines);
// log("dddd----_scrollToCurrentLine(optimized)----currentLineIndex:${currentLineIndex}---lastScrolled:${_lastScrolledLineIndex}");
// 只有当行索引改变时才滚动,避免重复滚动导致抖动
if (currentLineIndex >= 0 && currentLineIndex != _lastScrolledLineIndex) {
_scrollToIndexWithPreciseHeight(currentLineIndex);
setState(() {
// 触发_buildTranscript的重新构建以更新高亮
});
}
}
// 使用Scrollable.ensureVisible精确滚动到目标item
Scrollable.ensureVisible(
itemKey.currentContext!,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
alignment: 0.5, // 将目标item滚动到可视区域50%的位置
);
注意:如果itemKey是ListView的子item,如果item被回收会导致滚动失效
// 备用滚动方案:通过计算位置进行滚动
void _scrollToIndexAlternative(int targetIndex) {
ScrollController? scrollController = PrimaryScrollController.of(context);
if (scrollController == null || !scrollController.hasClients) return;
// 估算每个item的高度
// 包含:上下padding(33.w*2) + 播放按钮行(~60.w) + 间距(24.w) + 文本行(~60.w) = 约210.w
double estimatedItemHeight = 210.w;
double targetOffset = targetIndex * estimatedItemHeight;
// 确保不超过最大滚动范围
double maxOffset = scrollController.position.maxScrollExtent;
if (targetOffset > maxOffset) {
targetOffset = maxOffset;
}
scrollController.animateTo(
targetOffset,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
_lastScrolledLineIndex = targetIndex;
log("dddd----_scrollToIndexAlternative----scrolled to index:${targetIndex}, offset:${targetOffset}, estimatedHeight:${estimatedItemHeight}");
}