安卓开发之ScrollView嵌套ListView的一些问题和解决
2018-01-15 14:30
513 查看
一、ListView的高度不能完全展开
这种情况是当ScrollView嵌套ListView时,ListView的高度设置为wrap_content时会产生,一般情况下ListView只显示的第一个Item。正常情况下,高度设置为“wrap_content”的ListView在测量自己的高度会使用MeasureSpec.AT_MOST这个模式高度来返回可包含住其内容的高度。
而实际上当ListView被ScrollView嵌套时,ListView使用的测量模式是ScrollView传入的MeasureSpec.UNSPECIFIED。
// ScrollView的measureChildWithMargins()代码: @Override protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { ViewGroup.LayoutParams lp = child.getLayoutParams(); int childWidthMeasureSpec; int childHeightMeasureSpec; childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
而在ListView的onMeasure方法中:使用MeasureSpec.UNSPECIFIED模式测量时只能加载一部分高度。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Sets up mListPadding super.onMeasure(widthMeasureSpec, heightMeasureSpec); ... ... if (heightMode == MeasureSpec.UNSPECIFIED) { heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2; } setMeasuredDimension(widthSize, heightSize); mWidthMeasureSpec = widthMeasureSpec; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
解决方法一:覆写ListView的onMeasure方法:
import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.widget.ListView; /** * Created by cxm on 2016/9/15. */ public class MyListView extends ListView { public MyListView(Context context) { super(context); } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); } public MyListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public MyListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2, // 设计一个较大的值和AT_MOST模式 MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, newHeightMeasureSpec);//再调用原方法测量 } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
解决方法二:在Activity中动态修改ListView的高度,注意当ListView的子item需要根布局是LinearLayout,或需要为一个View,因为有些布局中没有measure这个方法,比如RelativeLayout。
public void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); // 获取item高度 totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); // 最后再加上分割线的高度和padding高度,否则显示不完整。 params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1))+listView.getPaddingTop()+listView.getPaddingBottom(); listView.setLayoutParams(params); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
缺陷:上述两种解决方法都有一个缺陷就是,当第一次进入界面动态加载listview的i数据后,ScrollView会跳滑到listview的第一个子项。处理缺陷可以有两种方式:
方式一:
先设置ListView失去焦点,这并不影响item的点击事件发生
.setFocusable(false);1
2
方式二:
重新调整ScrollView的位置
mScrollView.post(new Runnable() { @Override public void run() { mScrollView.scrollTo(0,0); } });1
2
3
4
5
6
7
二、ListView高度固定后无法触发滑动时间
当对listview的高度设置为固定值(例200dp)时,listview的高度是可以直接显示出来的。但嵌套在一起后ScrollView中的ListView就没法上下滑动了,事件先被ScrollView响应了。解决方法:当ListView自身接收到的滑动事件时,使ScrollView取消拦截。ListView区域内的滑动事件由自己处理,ListView区域外滑动事件由外层ScrollView处理。可以系统自带的API来实现:requestDisallowInterceptTouchEvent这一方法。
解决方法一:在这里我们自定义ListView来重写ListView的dispatchTouchEvent函数:
import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ListView; /** * Created by cxm on 2016/9/15. */ public class ScollListView extends ListView { public ScollListView(Context context) { super(context); } public ScollListView(Context context, AttributeSet attrs) { super(context, attrs); } public ScollListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ScollListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: getParent().requestDisallowInterceptTouchEvent(false); break; } return super.dispatchTouchEvent(ev); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
解决方式二:或者也可以给ListView绑定触摸事件的监听:
scrollListView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: scrollListView.getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: scrollListView.getParent().requestDisallowInterceptTouchEvent(false); break; } return false; } });1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
三、demo演示效果图:
Demo代码地址:Github
相关文章推荐
- 安卓开发之ScrollView嵌套ListView的一些问题和解决
- 安卓开发——问题:ScrollView中嵌套ListView时,listview只显示一行
- Android开发自定义ListView解决在NestedScrollView里不能用listview的问题(ScrollView嵌套ListView的问题)
- Android开发--解决ScrollView中嵌套ListView问题
- 解决ScrollView中listview、gridview的嵌套问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题(冲突)
- 开发笔记:解决安卓GestureOverlayView手势和ListView点击事件、文本框获取焦点冲突的问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- 解决scrollView嵌套listview的冲突问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- Android ScrollView中嵌套ListView滚动效果冲突问题解决
- 解决scrollview 嵌套gridview或者listview 冲突的问题
- 通过自定义ListView解决在scrollView中的嵌套问题
- 安卓开发中所遇到的一些问题及解决办法,不断更新中
- 解决ScrollView中嵌套ListView滚动效果冲突问题 & ListVIew点击事件失效
- Android:ScrollView 与 ListView 四种解决嵌套问题方法
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- 解决ScrollView下嵌套ListView进页面不在顶部的问题
- ScrollView中嵌套ListView滚动效果冲突问题解决
- 解决ScrollView下嵌套ListView或Gridview进页面不在顶部的问题