保存ScrollView位置失效求助:横竖屏切换无法精准恢复位置
解决ScrollView横竖屏切换后精准恢复滚动位置的问题
我太懂你这个痛点了——用常规保存scrollX/scrollY的方法,在横竖屏UI不同的场景下完全没法精准恢复位置,要么找不到原来的标题,要么直接滚到奇怪的地方,简直头疼。
问题出在哪?
你当前的代码是直接保存了ScrollView的滚动坐标,但横竖屏切换时,整个布局的尺寸、子View的位置都会发生大幅变化,原来的scrollY值在新布局里已经完全不对应原来的标题位置了,自然没法精准定位。
靠谱的改进方案
我们换个思路:保存你想要锚定的那个标题View的标识,而不是直接存滚动坐标,等布局完全加载完成后,直接滚动到该View的顶部。这样不管布局怎么变,都能精准定位到目标标题。
下面是具体实现代码:
1. 保存目标标题的标识
这里以保存标题View的id为例(如果是动态生成的标题,也可以存文本内容或者它在子View中的索引):
private static final String TARGET_TITLE_ID = "target_title_id"; @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 假设mCurrentTopTitle是当前顶部显示的标题View if (mCurrentTopTitle != null) { outState.putInt(TARGET_TITLE_ID, mCurrentTopTitle.getId()); } }
2. 恢复时精准滚动到目标标题
恢复的时候,先找到对应的标题View,再等布局完全测量完成后滚动——这一步很关键,避免布局没加载完就滚动导致位置错误:
@Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState == null) return; int targetId = savedInstanceState.getInt(TARGET_TITLE_ID, -1); if (targetId == -1) return; final View targetTitle = findViewById(targetId); if (targetTitle == null) return; // 监听布局完成事件,确保View尺寸和位置都已确定 mScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听,防止重复触发 mScrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // 滚动到目标标题的顶部 mScrollView.scrollTo(0, targetTitle.getTop()); } }); }
动态标题的适配(如果你的标题是动态生成的)
如果标题是动态添加到ScrollView的,没法用固定id,可以改为保存标题的文本内容,恢复时遍历ScrollView的子View找到匹配的那个:
// 保存时 outState.putString(TARGET_TITLE_TEXT, mCurrentTopTitle.getText().toString()); // 恢复时 String targetText = savedInstanceState.getString(TARGET_TITLE_TEXT); if (targetText != null) { // 遍历子View找对应标题 for (int i = 0; i < mScrollView.getChildCount(); i++) { View child = mScrollView.getChildAt(i); if (child instanceof TextView && targetText.equals(((TextView) child).getText().toString())) { // 找到后执行滚动逻辑,同上 break; } } }
为什么你原来的代码没效果?
你用post(Runnable)虽然能延迟执行,但有时候布局还没完全完成,子View的位置和尺寸还没计算好,这时候调用scrollTo用的还是旧布局的坐标,自然定位不准。而OnGlobalLayoutListener会在布局完全测量、排版完成后触发,这时候获取的targetTitle.getTop()才是新布局里的准确位置。
内容的提问来源于stack exchange,提问作者Ivan Bumbak
相关产品推荐
相关产品推荐

