天天看點

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就是你擷取資料後設定的,也就是上面兩點的綜合

繼續閱讀