这里的问题是在 ScrollView 中包含 ListView。下面给出的步骤描述了如何将 任何 垂直可滚动视图封装到另一个可垂直滚动视图中。
第一步
编写一个确定视图是否可以垂直滚动的方法,并将该方法放在一个通用实用程序类中,如下所示。该方法取自 ViewPager.java 并修改为查看 View 是否可以垂直滚动。
public static boolean canScroll(View v, boolean checkV, int dy, int x, int y) {
if (v instanceof ViewGroup) {
final ViewGroup group = (ViewGroup) v;
final int scrollX = v.getScrollX();
final int scrollY = v.getScrollY();
final int count = group.getChildCount();
for (int i = count - 1; i >= 0; i--) {
final View child = group.getChildAt(i);
if (x + scrollX >= child.getLeft()
&& x + scrollX < child.getRight()
&& y + scrollY >= child.getTop()
&& y + scrollY < child.getBottom()
&& canScroll(child, true, dy,
x + scrollX - child.getLeft(), y + scrollY
- child.getTop())) {
return true;
}
}
}
return checkV && ViewCompat.canScrollVertically(v, -dy);
}
第 2 步
子类化封闭的垂直可滚动视图,它可以是 ScrollView 或 ListView(在您的情况下是 ScrollView)等,并覆盖 onInterceptTouchEvent() 方法,如下所示。
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
float x = event.getX();
float y = event.getY();
float dy = y - mLastMotionY;
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
if (Util.canScroll(this, false, (int) dy, (int) x, (int) y)) {
mLastMotionY = y;
return false;
}
break;
}
return super.onInterceptTouchEvent(event);
}
第 3 步
子类化封闭的垂直可滚动视图,它可能是 GridView 或 ListView 等(在您的情况下为ListView)并覆盖 onMeasure() 方法,如下所示。无需在 ScrollView 中重写此方法。它的默认实现以正确的方式运行。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode == MeasureSpec.UNSPECIFIED) {
int height = getLayoutParams().height;
if (height > 0)
setMeasuredDimension(getMeasuredWidth(), height);
}
}
第四步
最后创建一个 xml 布局文件并使用您子类化的 ScrollView 和 ListView,并且您必须对 layout_height 进行硬编码。如果您通过 java 代码创建视图层次结构,则将高度硬编码为LayoutParams。如果您使用自己的测量策略而不是第 3 步中指定的测量策略,则不需要这种硬编码。
更多详情请查看ScrollInsideScroll这个帖子,下载项目并检查代码。