android scrollview嵌套listview计算高度的问题

时间:2023-03-09 03:37:20
android scrollview嵌套listview计算高度的问题

ScrollView中只能放一个控件,一般都放LinearLayout,orientation属性值为vertical。在LinearLayout中放需要呈现的内容。ListView也在其中,ListView的高度设为适应自身内容(wrap_content)。但是为啥在scrollview中嵌套listview会出现只显示第一条listitem的高度呢,原因是:scrollview的ontach方法的滚动事件消费处理,ListView控件的高度设定问题

从谷歌那里找到的ScrollView嵌套ListView只显示一行的解决办法相信很多人都遇到过,然后大部分都是用这位博主的办法解决的吧

刚开始我也是用这个办法解决的,首先感谢这位哥的大私奉献,贴上地址

http://blog.csdn.net/p106786860/article/details/10461015

2、解决的核心代码

  1. public void setListViewHeightBasedOnChildren(ListView listView) {
  2. // 获取ListView对应的Adapter
  3. ListAdapter listAdapter = listView.getAdapter();
  4. if (listAdapter == null) {
  5. return;
  6. }
  7. int totalHeight = 0;
  8. for (int i = 0, len = listAdapter.getCount(); i < len; i++) {
  9. // listAdapter.getCount()返回数据项的数目
  10. View listItem = listAdapter.getView(i, null, listView);
  11. // 计算子项View 的宽高
  12. listItem.measure(0, 0);
  13. // 统计所有子项的总高度
  14. totalHeight += listItem.getMeasuredHeight();
  15. }
  16. ViewGroup.LayoutParams params = listView.getLayoutParams();
  17. params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
  18. // listView.getDividerHeight()获取子项间分隔符占用的高度
  19. // params.height最后得到整个ListView完整显示需要的高度
  20. listView.setLayoutParams(params);
  21. }

这个代码让控件去计算Listview自己的高度然后设置这个Listview的高度

但是这个代码里面有一个问题,就是这个当你的ListView里面有多行的TextView的话,ListView的高度就会计算错误,它只算到了一行TextView的高度,

这个问题在so上的概述为以下:

http://*.com/questions/14386584/getmeasuredheight-of-textview-with-wrapped-text

3、终极解决办法

这个问题头疼了一阵后,查找了一下,应该重写一个TextView的onMeasure方法比较好解决

代码有

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. Layout layout = getLayout();
  5. if (layout != null) {
  6. int height = (int)FloatMath.ceil(getMaxLineHeight(this.getText().toString()))
  7. + getCompoundPaddingTop() + getCompoundPaddingBottom();
  8. int width = getMeasuredWidth();
  9. setMeasuredDimension(width, height);
  10. }
  11. }
  12. private float getMaxLineHeight(String str) {
  13. float height = 0.0f;
  14. float screenW = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth();
  15. float paddingLeft = ((LinearLayout)this.getParent()).getPaddingLeft();
  16. float paddingReft = ((LinearLayout)this.getParent()).getPaddingRight();
  17. //这里具体this.getPaint()要注意使用,要看你的TextView在什么位置,这个是拿TextView父控件的Padding的,为了更准确的算出换行
  18. 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开始测量时,测量到TextView时,就调用我们的onMeasure方法,我们就可以测量字体的总宽度除与去掉边距的屏幕的大小,就可以算出文字要几行来显示,然后测量字体的高度*行数可以得到字体的总高度,然后在加上上下边距就是TextView真正的高度,然后setMeasuredDimension进去就可以计算出正确的值出来。

完整大代码我贴出来

public class MyListView2 extends LinearLayout {

private BaseAdapter adapter;

private MyOnItemClickListener onItemClickListener;

boolean footerViewAttached = false;

private View footerview;





@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

// TODO Auto-generated method stub

super.onLayout(changed, l, t, r, b);

}





@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,

MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, expandSpec);

}









public void notifyChange() {

int count = getChildCount();

if (footerViewAttached) {

count--;

}

LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,

LayoutParams.WRAP_CONTENT);

for (int i = count; i < adapter.getCount(); i++) {

final int index = i;

final LinearLayout layout = new LinearLayout(getContext());

layout.setLayoutParams(params);

layout.setOrientation(VERTICAL);

View v = adapter.getView(i, null, null);

v.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

if (onItemClickListener != null) {

onItemClickListener.onItemClick(MyListView2.this,

layout, index, adapter.getItem(index));

}

}

});

ImageView imageView = new ImageView(getContext());

imageView.setLayoutParams(params);

layout.addView(v);

layout.addView(imageView);

addView(layout, index);

}

}





public MyListView2(Context context) {

super(context);

initAttr(null);

}





public MyListView2(Context context, AttributeSet attrs) {

super(context, attrs);

initAttr(attrs);

}





public void initAttr(AttributeSet attrs) {

setOrientation(VERTICAL);

}





public void initFooterView(final View footerView) {

this.footerview = footerView;

}





public void setFooterViewListener(OnClickListener onClickListener) {

this.footerview.setOnClickListener(onClickListener);

}





public BaseAdapter getAdapter() {

return adapter;

}





public void setAdapter(BaseAdapter adpater) {

this.adapter = adpater;

removeAllViews();

if (footerViewAttached)

addView(footerview);

notifyChange();

}





public void setOnItemClickListener(MyOnItemClickListener onClickListener) {

this.onItemClickListener = onClickListener;

}





public void noMorePages() {

if (footerview != null && footerViewAttached) {

removeView(footerview);

footerViewAttached = false;

}

}





public void mayHaveMorePages() {

if (!footerViewAttached && footerview != null) {

addView(footerview);

footerViewAttached = true;

}

}





public static interface MyOnItemClickListener {

public void onItemClick(ViewGroup parent, View view, int position,

Object o);

}

}

这个adapter就是你获取数据后设置的,也就是上面两点的综合