2010-02-22 33 views
32

我目前正在嘗試在ScrollView中使用ListView。我從我讀過的東西知道這是看不起的,但我試圖通過顯示其所有行來完全展開ListView,因此不需要滾動。然而,我一直在掙扎,因爲如何告訴ListView完全展開以顯示其所有行,因爲它需要定義的高度。有沒有人知道在繪製之前計算完全展開的ListView的高度的方法?計算列表視圖的大小或如何告訴它完全展開

此問題主要源於您無法在另一個可滾動視圖內放置可滾動視圖的事實。我很滿意這樣一個事實,即只要我可以展開顯示其所有行,ListView就無法滾動。但是,我無法做到這一點,但沒有能夠給它一個確定的高度,這似乎我需要計算。

請參閱下面的網址以瞭解草圖(我是新用戶,所以我不允許發佈一個)。它顯示我的完整版面對於「物理」屏幕來說太大了,需要滾動才能顯示底部的列表和按鈕的其餘部分。我試圖弄清楚,即使沒有ListView,「虛擬」屏幕也太大而無法放在一個屏幕上。

http://img51.imageshack.us/img51/7210/screenmockup.png

+0

「完全展開」是什麼意思? – CommonsWare 2010-02-22 17:52:46

+0

完全展開,我的意思是顯示其所有行。這個問題被適當地編輯以解釋這一點。 – 2010-02-22 18:56:58

+0

如果您發佈了您正在嘗試完成的屏幕截圖或草圖,它可能會有所幫助。我很難理解爲什麼默認行爲「儘可能擴展,然後滾動,如果有太多項目不適合」是不夠的。 – 2010-02-22 19:43:33

回答

57

嗯,感謝魯迪,他的建議非常有幫助。這是如何實施的。

1)創建一個擴展的ListView一個新的類:

package com.example.android.views; 

import android.content.Context; 
import android.graphics.Canvas; 
import android.util.AttributeSet; 
import android.widget.ListView; 

public class ExpandedListView extends ListView { 

    private android.view.ViewGroup.LayoutParams params; 
    private int old_count = 0; 

    public ExpandedListView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     if (getCount() != old_count) { 
      old_count = getCount(); 
      params = getLayoutParams(); 
      params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0); 
      setLayoutParams(params); 
     } 

     super.onDraw(canvas); 
    } 

} 

2)...最後是新的視圖添加到您的XML佈局文件:

<com.example.android.views.ExpandedListView 
    android:id="@+id/list" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:scrollbars="none" 
    android:padding="0px" 
    /> 
+1

對我有用:) – 2011-12-21 19:42:24

+14

我還沒試過,但是從我看到的情況來看,它只有在所有元素與getChildAt(0)都具有相同高度的情況下才有效(或者如果運氣確切的話,平均尺寸大於'getChildAt(0).getHeight()') – 2013-03-20 20:19:01

+0

沒有人知道我會如何在Xamarin.Android中使用上面的代碼? – 2014-10-21 13:32:06

2

你不應該放在一個滾動型的ListView控件。 ListView已經可以滾動。

默認情況下,ListView應該完全展開,如果它是佈局中唯一的東西。

如果它不是佈局中的唯一東西,並且希望ListView展開佔據所有可用空間,請將ListView上的layout_weight設置爲1,其中layout_weight = 0。

<LinearLayout android:layout_width="fill_parent" 
      android:layout_height="fill_parent" orientation="vertical"> 
    <TextView id="@+id/title" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content"/> 
    <ListView id="@+id/listView" 
      android:layout_width="fill_parent" 
      android:layout_height="0dp" 
      android:layout_weight="1"/> 
</LinearLayout> 

編輯: ListView控件是真正設計成滾動的......你有屏幕布局在您的屏幕截圖並沒有真正看起來像「機器人方式」。但是,如果您真的想要規避這種情況,您可以嘗試對其中一行進行膨脹,獲取其minHeight,然後將其乘以ListView適配器中的項目數。

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
View view = inflater.inflate(R.layout.label_value_row, null, false); 
int height = adapter.getCount() * view.getMinHeight(); 
+0

但是,如果所有行都顯示,則ListView將不可滾動。我的問題是,我需要在佈局中顯示更多的視圖,而不是隻能在一個屏幕上顯示。我不希望ListView展開到屏幕,我希望它展開以顯示其所有行。 – 2010-02-22 19:16:56

+1

如果內容多於屏幕上的內容,ListView將自動滾動。從ListView API中,ListView是「顯示垂直滾動列表中的項目的視圖」。滾動內置。嘗試它! – 2010-02-22 19:20:27

+0

即使沒有ListView,屏幕上的其他視圖也不適合,因此我需要疊加視圖才能成爲ScrollView。我希望ListView的大小足以顯示其所有行。我可以通過在LayoutParams中給它設置一個高度來完成這個任務,但是這個列表是動態的,所以我想要找出一種方法來計算這個高度。請參閱我提供給問題的編輯。 – 2010-02-22 19:33:50

3

如果你想要一個不會滾動的ListView不能只使用LinearLayout?

+1

我想保留列表的本機android外觀,而不必滾動我自己的。 – 2010-02-22 19:18:19

+0

你的意思是突出狀態?如果是這樣,你可以使用android.R.drawable.list_selector_background來獲得我相信的那種行爲。 – jqpubliq 2010-02-22 19:26:07

+0

是的,除了默認的頁眉和頁腳功能,列出了漸變分隔符以及使用適配器結構。我最終可能會試圖通過複製所有內置的Android樣式來製作ListView的克隆,但如果可能的話,我想避免這種情況。 – 2010-02-22 19:31:37

0

我最終重寫了ListView的onDraw(),並計算視圖中可見行的平均高度,然後根據適配器中有多少項目來估計列表的實際高度。這種估計會發生幾次,直到所有行都可見。

1

我一直在研究如何做到這一點,雖然問題已經回答了,我想提供一個解決方案,我認爲更好:

在ListView控件的源代碼,看你可以看到onMeasure(...)裏面的代碼如下:

if (heightMode == MeasureSpec.AT_MOST) { 
    // TODO: after first layout we should maybe start at the first visible position, not 0 
    heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1); 
} 

所以只需調用ListView的措施,並通過MeasureSpec.AT_MOST的高度,而不是通常的MeasureSpec.UNSPECIFIED。

我做以下衡量一個列表視圖,並把它彈出的窗口內:

int widthMeasureSpec = MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, MeasureSpec.EXACTLY); 
    int heightMeasureSpec = MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, MeasureSpec.AT_MOST); 
    mCatalogView.measure(widthMeasureSpec, heightMeasureSpec); 

    mPopup.setWidth(mCatalogView.getMeasuredWidth()); 
    mPopup.setHeight(mCatalogView.getMeasuredHeight()); 
11

注意! 計算高度正確的方法是不

params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0); 

我們必須添加的每個(負一)分隔高度的高度。

if(oldCount > 0 && getCount() > 0) 
    params.height = getCount() 
        * (getChildAt(0).getHeight() + getDividerHeight()) 
        - getDividerHeight(); 
else 
    params.height = 0; 
+1

請注意,這種解決方案仍然假設所有項目都是相同的高度,並且沒有頁腳和頁眉 – 2015-01-23 14:47:13

+0

listView.getChildAt(0)爲null – AndroidGuy 2018-02-26 07:54:16

13

計算高度的正確方法是準確的說:

int height = 0; 
for (int i = 0; i < listView.getChildCount(); i++) { 
    height += listView.getChildAt(i).getMeasuredHeight(); 
    height += listView.getDividerHeight(); 
} 
4
@Override 
public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 
    if (this.isExpanded) { 
     final int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); 
     super.onMeasure(widthMeasureSpec, expandSpec); 
     final ViewGroup.LayoutParams params = this.getLayoutParams(); 
     params.height = this.getMeasuredHeight(); 
    } else { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    } 
} 
1

我把功能從djunod的回答(在靜態類中的函數)

calculate listview size

並改變提取方法如下。 它在刪除操作成功後起作用。

這裏是我的最後一節課

類ExpandedListView擴展的ListView {

private android.view.ViewGroup.LayoutParams params; 
private int old_count = 0; 

public ExpandedListView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
} 

@Override 
protected void onDraw(Canvas canvas) { 

    if (getCount() != old_count) { 
     params = getLayoutParams(); 
     old_count = getCount(); 
     int totalHeight = 0; 
     for (int i = 0; i < getCount(); i++) { 
      this.measure(0, 0); 
      totalHeight += getMeasuredHeight(); 
     } 

     params = getLayoutParams(); 
     params.height = totalHeight + (getDividerHeight() * (getCount() - 1)); 
     setLayoutParams(params); 
    } 

    super.onDraw(canvas); 
} 

}

現在我的列表視圖行插入擴展後無需滾動。 和行後刪除此代碼計算列表視圖的正確大小。 我不知道它是如何工作的。 但它工作。 BR

+0

「我不知道它是如何工作的,但它工作正常」大聲笑 – Shaegorath 2014-09-21 07:02:07

+0

這工作正常,我不沒有如何正常工作,但工作正常。 – 2014-12-01 17:03:48

0

我知道它的晚,已經有和的答案,但如果你真的想這樣做有一個簡單的方法:

具有定義高度

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="100dp" 
    android:orientation="horizontal" > 

    <ImageView 
     android:id="@+id/lvItemSurpriseMeImgRestaurant" 
     android:layout_width="80dp" 
     android:layout_height="80dp" 
     android:layout_marginLeft="5dp" 
     android:contentDescription="@string/restaurantImageDescriptionColon" /> 
</LinearLayout> 

創建列表視圖項目現在我們知道該項目是100dp高,如果我們知道項目的數量,那麼它是非常簡單的

設置ListView高度字面上的值爲NoOfItems * Height + 10dp多餘

它永遠不會改變,因爲所有單位在dp

如果你有超過1種項目類型,然後用基本的數學計算設定它

 <ListView 
      android:id="@+id/menuListView" 
      android:layout_width="match_parent" 
      android:layout_height="210dp" 
      android:layout_weight="1.0" 
      tools:ignore="NestedScrolling" 
      tools:listitem="@layout/menu_item" > 
     </ListView> 
+0

不處理高度不同的行,例如長文本換行時。 – Justin 2014-08-15 01:53:14

+0

我建議您嘗試使用elipsize(不確定的拼寫),但它不會讓文本超過使用最大行數設置的限制以上,因爲我是從手機搜索 – 2014-08-15 05:31:26

+0

省略號不適用於我案件。必須以編程方式計算大小以擴大列表視圖 – 2016-04-26 01:05:53

0

如果你有不同高度的項目,你需要使用這個方法:

public void setListViewHeightBasedOnChildren(ListView listView) { 

    ListAdapter listAdapter = listView.getAdapter(); 
    if (listAdapter != null) { 

     int numberOfItems = listAdapter.getCount(); 

     // Get total height of all items. 
     int totalItemsHeight = 0; 
     for (int itemPos = 0; itemPos < numberOfItems; itemPos++) { 
      View item = listAdapter.getView(itemPos, null, listView); 
      float px = 300 * (listView.getResources().getDisplayMetrics().density); 
      item.measure(
        View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST), 
        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); 
      int height = item.getMeasuredHeight(); 
      totalItemsHeight += height; 
     } 

     // Get total height of all item dividers. 
     int totalDividersHeight = listView.getDividerHeight() * 
       (numberOfItems - 1); 

     // Set list height. 
     ViewGroup.LayoutParams params = listView.getLayoutParams(); 
     params.height = totalItemsHeight + totalDividersHeight; 
     listView.setLayoutParams(params); 
     listView.requestLayout(); 
    } 
} 

它任何ListView與任何項目工作得很好

+0

如果您的列表包含大約1000個項目,則這不起作用並凍結UI。我甚至嘗試刪除for循環和getView只爲0項目。即使如此,bindView方法被調用1000次.. :( – AndroidGuy 2018-02-26 06:29:19

+0

好吧,當UI試圖同時呈現1000個元素時,你會發現什麼? – 2018-03-07 17:50:10

1

使用此將工作:

public class ListViewEx extends ListView { 

public ListViewEx(Context context) { 
    super(context); 
} 

/** 
* @param context 
* @param attrs 
*/ 
public ListViewEx(Context context, AttributeSet attrs) { 
    super(context, attrs); 
} 

/** 
* 設置不滾動 
*/ 
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST); 
    super.onMeasure(widthMeasureSpec, expandSpec); 
} 

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) { 
    return ev.getAction()==MotionEvent.ACTION_MOVE||super.dispatchTouchEvent(ev); 
} 

}

相關問題