求助:ScrollView在子TextView修改Span时停止滚动的问题
解决ScrollView因TextView Span更新停止滚动的问题
我来帮你搞定这个头疼的问题~ 当你每秒更新TextView里的Span时,ScrollView会停止滚动,本质原因是Span的修改会触发TextView的内容变更通知,ScrollView会误以为内容发生了实质性变化,从而重置滚动状态。下面是具体的解决步骤和代码优化方案:
核心思路
在更新Span前后,手动保存并恢复ScrollView的滚动位置,避免系统自动重置滚动状态。同时,别忘了清理旧的Span,避免性能问题和显示异常。
1. 保存并恢复滚动位置
修改你的onUpdateTime Runnable,在更新Span前记录当前滚动位置,更新完成后再恢复:
private Runnable onUpdateTime = new Runnable() { @Override public void run() { // 1. 保存当前ScrollView的滚动位置 int savedScrollY = m_scrollView.getScrollY(); // 2. 执行Span更新操作 changeTextViewSpan(); // 3. 恢复滚动位置,用post确保在视图更新后执行,避免无效操作 m_scrollView.post(() -> { m_scrollView.scrollTo(0, savedScrollY); }); m_mainLayout.postDelayed(onUpdateTime, 1000); } };
2. 清理旧Span避免叠加
每次设置新Span前,先移除之前的下划线Span,不然Span会不断累积,既影响性能也可能导致显示错误:
private void changeTextViewSpan() { // 先移除已存在的下划线Span m_spannableText.removeSpan(m_underlineSpan); // 再设置新的Span范围 m_spannableText.setSpan( m_underlineSpan, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); }
额外优化建议
如果你的场景需要支持用户手动滚动时不被恢复操作打断,可以添加滚动状态判断:
- 给ScrollView设置
OnScrollChangeListener,记录是否处于用户手动滚动状态 - 在恢复滚动位置前,判断如果不是用户手动滚动,再执行恢复操作
示例代码(可选):
private boolean isUserScrolling = false; // 在onCreate里设置滚动监听 m_scrollView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> { // 判断是否是用户手动滚动(简单判断:滚动前后位置变化,且不是代码触发的滚动) isUserScrolling = scrollY != oldScrollY; }); // 然后在恢复滚动位置时判断 m_scrollView.post(() -> { if (!isUserScrolling) { m_scrollView.scrollTo(0, savedScrollY); } });
这样就能完美解决Span更新导致ScrollView停止滚动的问题啦~
内容的提问来源于stack exchange,提问作者arek
相关产品推荐
相关产品推荐

