问题原因:scroll事件的消费处理以及ListView控件的高度设定问题。
1、手动设置ListView高度
经过测试发现,在xml中直接指定ListView的高度,是可以解决这个问题的,但是ListView中的数据是可变的,实际高度还需要实际测量。于是手动设置ListView高度的方法可以解决。在listview设置adapter后,使用以下方法即可:
- /**
- * 动态设置ListView的高度
- * @param listView
- */
- public static void setListViewHeightBasedOnChildren(ListView listView) {
- if(listView == null) return;
- ListAdapter listAdapter = listView.getAdapter();
- if (listAdapter == null) {
- // pre-condition
- return;
- }
- int totalHeight = 0;
- for (int i = 0; i < listAdapter.getCount(); i++) {
- View listItem = listAdapter.getView(i, null, listView);
- listItem.measure(0, 0);
- totalHeight += listItem.getMeasuredHeight();
- }
- ViewGroup.LayoutParams params = listView.getLayoutParams();
- params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
- listView.setLayoutParams(params);
- }
一是Adapter中getView方法返回的View的必须由LinearLayout组成,因为只有LinearLayout才有measure()方法,如果使用其他的布局如RelativeLayout,在调用listItem.measure(0, 0);时就会抛异常,因为除LinearLayout外的其他布局的这个方法就是直接抛异常的。
二是需要手动把ScrollView滚动至最顶端,因为使用这个方法的话,默认在ScrollView顶端的项是ListView,具体原因不了解。
2、自定义可适应ScrollView的ListView
这个方法和上面的方法是异曲同工,方法3是自定义了LinearLayout以取代ListView的功能,但如果我脾气就是倔,就是要用ListView怎么办?那就只好自定义一个类继承自ListView,通过重写其onMeasure方法,达到对ScrollView适配的效果。
下面是继承了ListView的自定义类:
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.ListView;
- public class ListViewForScrollView extends ListView {
- public ListViewForScrollView(Context context) {
- super(context);
- }
- public ListViewForScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public ListViewForScrollView(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- }
- @Override
- /**
- * 重写该方法,达到使ListView适应ScrollView的效果
- */
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
- MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
- }
这个方法和方法1有一个同样的毛病,就是默认显示的首项是ListView,需要手动把ScrollView滚动至最顶端。
gridview的:
public void fixGridViewHeight(GridView gridView) {
GridviewAdapter gridAdapter = (GridviewAdapter) gridView.getAdapter();
int totalHeight = 0;
if (gridAdapter == null) {
return;
}
int addHeight = 0;
int lineNum = 0;
int height = 0;
for (int index = 0, len = gridAdapter.getCount(); index < len; index++) {
View listViewItem = gridAdapter.getView(index , null, gridView);
// 计算子项View 的宽高
listViewItem.measure(0, 0);
if(addHeight==0){
// 计算所有子项的高度和
totalHeight += listViewItem.getMeasuredHeight();
height=listViewItem.getMeasuredHeight();
addHeight=2;
lineNum++;
}else{
if(height<listViewItem.getMeasuredHeight()){
totalHeight=totalHeight-height;
totalHeight += listViewItem.getMeasuredHeight();
height=listViewItem.getMeasuredHeight();
}
addHeight--;
}
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight+(gridView.getVerticalSpacing() * (lineNum - 1)+8);
gridView.setLayoutParams(params);
}