ScrollView的scrollTo方法失效求助:折叠ExpandableTextView后视图不上移
问题分析与解决方案
咱们先拆解你遇到的两个核心问题,再一步步解决:
1. 为什么scrollTo没效果?——布局更新的异步性
当你点击按钮折叠ExpandableTextView时,视图的高度变化并不会立刻完成,Android的布局重绘、测量是异步执行的。你之前在点击后立刻调用scrollTo,或者在onCreate/AsyncTask.onPostExecute里调用,都是在布局还没完成更新的时候执行的,这时候descTxt.getTop()的值还是折叠前的旧值,或者ScrollView还没重新计算自己的滚动范围,自然不会有效果。
2. 隐藏的坑:ScrollView嵌套ListView的冲突
ScrollView和ListView都是滚动容器,嵌套在一起时,ListView默认只会显示一行的高度,而且会干扰ScrollView的整体布局测量——这会导致整个ScrollView的滚动计算逻辑混乱,也是你后续操作失效的潜在原因,必须先解决这个问题。
第一步:修复ScrollView嵌套ListView的布局问题
自定义一个ListView,让它能在ScrollView里完全展开,计算所有子项的总高度:
public class FullHeightListView extends ListView { public FullHeightListView(Context context) { super(context); } public FullHeightListView(Context context, AttributeSet attrs) { super(context, attrs); } public FullHeightListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 让ListView测量所有子项的总高度,而不是只显示一行 int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }
然后把布局里的原生ListView替换成这个FullHeightListView。
第二步:让ScrollView在布局更新完成后再滚动
利用View.post()方法,它会在视图完成重绘和布局计算后再执行Runnable,保证我们拿到的是最新的布局位置:
修改你的按钮点击事件:
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 先执行折叠/展开操作 boolean isCurrentlyExpanded = ...; // 你的判断逻辑,比如记录当前状态 if (isCurrentlyExpanded) { descTxt.collapse(); // 调用你的ExpandableTextView折叠方法 } else { descTxt.expand(); // 调用你的ExpandableTextView展开方法 } // 等到布局更新完成后再执行滚动 final ScrollView sv = (ScrollView) findViewById(R.id.sv); sv.post(new Runnable() { @Override public void run() { // 折叠状态下,滚动到ExpandableTextView的顶部 if (!descTxt.isExpanded()) { // 假设你的控件有isExpanded()方法判断状态 sv.scrollTo(0, descTxt.getTop()); } } }); } });
如果你的ExpandableTextView库自带状态变化回调(比如很多第三方库有OnExpandStateChangeListener),可以直接在回调里处理,这样时机更准确:
descTxt.setOnExpandStateChangeListener(new ExpandableTextView.OnExpandStateChangeListener() { @Override public void onExpandStateChanged(TextView textView, boolean isExpanded) { final ScrollView sv = (ScrollView) findViewById(R.id.sv); sv.post(new Runnable() { @Override public void run() { if (!isExpanded) { sv.scrollTo(0, descTxt.getTop()); } } }); } });
为什么之前的尝试没用?
onCreate时:视图还没完成初始化和布局,descTxt.getTop()的值是不准确的;AsyncTask.onPostExecute时:ListView加载完成了,但此时ExpandableTextView的折叠操作还没触发,或者布局还没进入稳定状态,调用scrollTo自然无效。
内容的提问来源于stack exchange,提问作者Simos
相关产品推荐
相关产品推荐

