出處:http://m.blog.csdn.net/blog/yhc13429826359/39058973
在之前的編程裏,我還沒有遇到過要在一個ListView中嵌套一個GridView或是在一個GridView中嵌套一個ListView。所以今天事兒來了!我花了一將近3個小時,找到了爲什麼我在一個ListView中添加一個GridView時,只顯示一行GridView的原因;另外,這3個小時的付出,又讓我學會了另一件事——在局部找不到原因的時候,要跳出來,從更大的範圍尋找原因。廢話了這麼多,那麼究竟是爲什麼只顯示一行GridView呢?
因爲在Android中,有這樣一個限制,兩ScrollView型的控件不能相互嵌套。像ListView和GridView就都是ScrollView型的控件。因爲嵌套後,兩個ScrollView型控件的滑動效果就喪失了,同時被嵌套控件的高度也被限定爲一行的高度。那我們還能不能嵌套兩個ScrollView型的控件呢?肯定是可以的。方法有兩種:一是我們去需要自定義ListView或是GridView,並重寫其onMeasure()方法。如下:
public class NoScrollGridView extends GridView {
public NoScrollGridView(Context context) {
super(context);
}
public NoScrollGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
ListView也同理。
還有一種方法是我們重新動態地計算我們現在需要的高度。在我們調用Adapter的時候,我們獲得現在這個時候的GridView有多少個,單個GridView的高度,然後計算總高度。具體代碼如下:
<span style="white-space:pre"> </span>/**
* 重新計算listView高度
* @param listView
*/
public static 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 < len; i++) { // listAdapter.getCount()返回數據項的數目
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0); // 計算子項View 的寬高
totalHeight += listItem.getMeasuredHeight(); // 統計所有子項的總高度
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
// listView.getDividerHeight()獲取子項間分隔符佔用的高度
// params.height最後得到整個ListView完整顯示需要的高度
listView.setLayoutParams(params);
}
在我們setAdapter()的之前,我們調用上面的方法,如setListViewHeightBasedOnChildren(accomplishmentStateListView);
因爲我是在ListView中嵌套GridView,所以重新計算GridView的總高度的時候,要放在setAdapter(...GridViewAdapter)這個BaseAdapter的衍生類裏。代碼如下:
<span style="white-space:pre"> </span>/**
* 計算gridview高度
* @param gridView
*/
public static void setGridViewHeightBasedOnChildren(GridView gridView) {
// 獲取GridView對應的Adapter
ListAdapter listAdapter = gridView.getAdapter();
if (listAdapter == null) {
return;
}
int rows;
int columns = 0;
int horizontalBorderHeight = 0;
Class<?> clazz = gridView.getClass();
try {
// 利用反射,取得每行顯示的個數
Field column = clazz.getDeclaredField("mRequestedNumColumns");
column.setAccessible(true);
columns = (Integer) column.get(gridView);
// 利用反射,取得橫向分割線高度
Field horizontalSpacing = clazz
.getDeclaredField("mRequestedHorizontalSpacing");
horizontalSpacing.setAccessible(true);
horizontalBorderHeight = (Integer) horizontalSpacing.get(gridView);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
// 判斷數據總數除以每行個數是否整除。不能整除代表有多餘,需要加一行
if (listAdapter.getCount() % columns > 0) {
rows = listAdapter.getCount() / columns + 1;
} else {
rows = listAdapter.getCount() / columns;
}
int totalHeight = 0;
for (int i = 0; i < rows; i++) { // 只計算每項高度*行數
View listItem = listAdapter.getView(i, null, gridView);
listItem.measure(0, 0); // 計算子項View 的寬高
totalHeight += listItem.getMeasuredHeight(); // 統計所有子項的總高度
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight + horizontalBorderHeight * (rows - 1);// 最後加上分割線總高度
gridView.setLayoutParams(params);
}
這樣我們就可以在ListView中添加GridView了。。。
注:兩個SrcollView型的控件可以是:
<ListView, GridView>;
<GridView,ListView>;
<ListView,ListView>;
<GridView, GridView>;
<ListView, ScrollView>;
<ScrollView,ListView>;
<GridView, ScrollView>;
<ScrollView, GridView>;
<ScrollView, ScrollView>;