You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用ScrollView与TextView滚动异常问题排查与解决

这个问题我在做Android 10适配的时候踩过坑,是SDK29(Android Q)特有的ScrollView与软键盘交互的bug,给你拆解下成因和可行的解决办法:

问题成因
  1. adjustPan模式下的核心bug:Android 10在处理adjustPan模式时,ScrollView的内部滚动逻辑出现了布局计算异常。当软键盘弹出后,系统会将窗口向上平移以聚焦输入框,但ScrollView没有正确更新整个子视图的滚动范围锚点——导致滚动上半部分内容时,下半部分的视图因为布局锚点未刷新而固定在原位置。
  2. adjustResize的间接问题:你提到用adjustResize在基础应用里也出问题,大概率是因为你的Activity或根布局开启了全屏/沉浸式模式(比如设置了fitsSystemWindows="false",或者隐藏了状态栏),导致adjustResize的布局重计算信号被拦截,无法正确触发ScrollView的滚动范围更新,间接引发了类似的异常。
解决方案

方案1:自定义ScrollView修复SDK29的计算bug

这是最彻底的修复方式,通过重写ScrollView的onMeasure方法,强制在SDK29时重新计算子视图的尺寸,修正滚动锚点:

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.ScrollView

class QFixedScrollView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ScrollView(context, attrs, defStyleAttr) {

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        // 仅针对Android Q(SDK29)修复
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            getChildAt(0)?.let { child ->
                val childHeightSpec = MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.AT_MOST)
                child.measure(widthMeasureSpec, childHeightSpec)
            }
        }
    }
}

之后把布局里的<ScrollView>替换成<你的包名.QFixedScrollView>即可。

方案2:修复adjustResize不生效的问题

如果你的应用依赖adjustResize模式,需要确保以下几点:

  • 根布局设置android:fitsSystemWindows="true",让系统能正确计算布局与系统窗口的间距;
  • 在Activity的onCreate里添加代码,确保系统窗口的交互逻辑正常:
import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class YourActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            getWindow().setDecorFitsSystemWindows(true);
        }
    }
}
  • 检查是否有第三方库(比如全屏弹窗、悬浮窗)拦截了adjustResize的信号,如有需要临时禁用或调整相关逻辑。

方案3:临时绕过的快捷技巧

如果不想自定义View,可以通过监听键盘状态,手动触发ScrollView的布局刷新:

import android.graphics.Rect
import android.view.ViewTreeObserver
import android.widget.ScrollView

// 在Activity里添加监听
val scrollView = findViewById<ScrollView>(R.id.your_scroll_view)
scrollView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
    override fun onGlobalLayout() {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            val rect = Rect()
            scrollView.getWindowVisibleDisplayFrame(rect)
            val screenHeight = scrollView.rootView.height
            val keyboardHeight = screenHeight - rect.bottom
            // 当键盘高度超过屏幕15%时,判定为弹出状态
            if (keyboardHeight > screenHeight * 0.15) {
                scrollView.requestLayout()
                scrollView.invalidate()
            }
        }
    }
})

// 记得在Activity销毁时移除监听,避免内存泄漏
override fun onDestroy() {
    super.onDestroy()
    scrollView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}

内容的提问来源于stack exchange,提问作者finder2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:27:13