ListView与ScrollView混合使用主要有两种效果:
1、ListView在ScrollView中高度固定。滑动ListView时,ListView滚动。ListView到头或者滑动ScrollView时整个页面滚动。
listView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
scrollView.requestDisallowInterceptTouchEvent(false);
}else{
scrollView.requestDisallowInterceptTouchEvent(true);
}
return false;
}
});
2、整个ListView显示在ScrollView中,随ScrollView一起滑动。
实现原理:计算整个ListView的高度,填充数据后重新设置ListView高度。
listView.setAdapter(adapter);
setListViewHeightBasedOnChildren(listView);
<pre name="code" class="java">public static void setListViewHeightBasedOnChildren(ListView listView) {
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, View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED));
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
注意:一定要在填充完数据再设置高度。
正常情况下使用上面的方法就可以实现ListView的高度计算了,但有时会出现item中的TextView中数据过长而多行显示的问题,这时计算的高度就会出现偏差。
解决方法:目前网上找到的主要有两种,一是重写TextView(还没试过),二是重写ListView(正在使用)。
重写TextView中的onMeasure()方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Layout layout = getLayout();
if (layout != null) {
int height = (int)FloatMath.ceil(getMaxLineHeight(this.getText().toString()))
+ getCompoundPaddingTop() + getCompoundPaddingBottom();
int width = getMeasuredWidth();
setMeasuredDimension(width, height);
}
}
private float getMaxLineHeight(String str) {
float height = 0.0f;
float screenW = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth();
float paddingLeft = ((LinearLayout)this.getParent()).getPaddingLeft();
float paddingReft = ((LinearLayout)this.getParent()).getPaddingRight();
//这里具体this.getPaint()要注意使用,要看你的TextView在什么位置,这个是拿TextView父控件的Padding的,为了更准确的算出换行
int line = (int) Math.ceil( (this.getPaint().measureText(str)/(screenW-paddingLeft-paddingReft)));
height = (this.getPaint().getFontMetrics().descent-this.getPaint().getFontMetrics().ascent)*line;
return height;
}
重写ListView中的onMeasure()方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
ListView:
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
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
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
} catch (Exception e) {
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
this.requestDisallowInterceptTouchEvent(true);
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
}