天天看点

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

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

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

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

<a target="_blank" href="http://blog.csdn.net/p106786860/article/details/10461015">http://blog.csdn.net/p106786860/article/details/10461015</a>

2、解决的核心代码

public void setlistviewheightbasedonchildren(listview listview) {     

        // 获取listview对应的adapter     

        listadapter listadapter = listview.getadapter();     

        if (listadapter == null) {     

            return;     

        }     

        int totalheight = 0;     

        for (int i = 0, len = listadapter.getcount(); i &lt; len; i++) {     

            // listadapter.getcount()返回数据项的数目     

            view listitem = listadapter.getview(i, null, listview);     

            // 计算子项view 的宽高     

            listitem.measure(0, 0);      

            // 统计所有子项的总高度     

            totalheight += listitem.getmeasuredheight();      

        viewgroup.layoutparams params = listview.getlayoutparams();     

        params.height = totalheight+ (listview.getdividerheight() * (listadapter.getcount() - 1));     

        // listview.getdividerheight()获取子项间分隔符占用的高度     

        // params.height最后得到整个listview完整显示需要的高度     

        listview.setlayoutparams(params);     

    }     

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

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

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

<a target="_blank" href="http://stackoverflow.com/questions/14386584/getmeasuredheight-of-textview-with-wrapped-text">http://stackoverflow.com/questions/14386584/getmeasuredheight-of-textview-with-wrapped-text</a>

3、终极解决办法

这个问题头疼了一阵后,查找了一下,应该重写一个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开始测量时,测量到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);

}

protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {

int expandspec = measurespec.makemeasurespec(integer.max_value &gt;&gt; 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 &lt; 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() {

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 &amp;&amp; footerviewattached) {

removeview(footerview);

footerviewattached = false;

public void mayhavemorepages() {

if (!footerviewattached &amp;&amp; footerview != null) {

footerviewattached = true;

public static interface myonitemclicklistener {

public void onitemclick(viewgroup parent, view view, int position,

object o);

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

继续阅读