過兩天同學要回家相親結婚去了,昨晚作爲送行之聚,喝的是稀里嘩啦。早上起來喝了一杯牛奶後卻無所事事,所以乾脆把前幾天做項目時總結的一些知識梳理一下。
其實標題與本文不算太相符,這裏借標題引申出一個特殊的佈局,進而再去挖掘這種佈局的解決思路。這種佈局很常見,拿美團首頁來說,頂部是一些雜七麻八的佈局顯示一些分類模塊和熱門頻道之類的,中間是listview,底部是加載更多和其他模塊。
這種佈局有一個特點就是滑動屏幕可以整體滑動而不是僅僅中間的listview可以滑動,不由得就讓人突發奇想——scrollview嵌套listview。好想法,可是真正嵌套的時候卻發現listview本來一次性請求有10條數據卻顯示一條甚至還不完整,並且滑動listview只能在顯示一條數據的空間高度上滑動,好彆扭吧。造成這種結果的原因是scrollview作爲父級滑動控件,listview作爲孩子,那麼scrollview便會把listview的滑動效果給消費掉,造成listview不知道自身該有多高,也就不能展開了。google一下,android官方也不建議採用類似滑動嵌套滑動的這種奇怪佈局。但是需求擺在這裏,問題終歸要解決。知道了上邊的原因問題就好辦了。
1.動態計算listview的高度
/**
* 動態設置ListView的高度
* @param listView
*/
private void setListViewHeightBasedOnChildren(ListView listView) {
if(listView == null)
return;
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
2.自定義listview重寫onMeasure()方法
public class ListViewForScrollView extends ListView {
public ListViewForScrollView(Context context) {
super(context);
}
public ListViewForScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewForScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
方法1和方法2都有一些弊端:
a.顯示的時候先顯示的是listview的首項,而不是scrollview的頂部,所以視圖實例後現將scrollview滑動到頂端。
scrollview = (ScrollView) findViewById(R.id.scrollview);
scrollview.smoothScrollTo(0, 0);
b.最令我不能接受的,這樣動態計算獲取listview的高度,結果是有多少數據listview就顯示什麼樣的高度, 既全部顯示,你上下滑動的時候listview的重用機制就失效了,數據量大的話內存會一個勁的往上漲,這樣做是不合理的。當然數據量少的話是可以採用的,尤其是方法2,由listview重寫onMeasure一口氣測量,速度更快。
c.第一種方法的item必須是LinearLayout,是利用LinearLayout的measure()方法來測量的。
3.自定義LinearLayout來取代listview
既然scrollview裏嵌套listveiw的這種滑動嵌套滑動容易出現問題,我們何不用LinearLayout來取代listview。Linearlayout有一個addvie()方法,可以將每一個item添加進去形成LinearLayout的子項,這樣我們不需要計算高度的問題了。但是同樣有一個問題,還是不能重用。
4.爲listview設定一個高度。
遇到數據量大的情況,我們事先已經知道,那麼幹脆初步給listview預設一個高度,然後在嵌套在scrollview中,這樣既能重用數據,又能整體滑動,也不失爲一種解決方法。
5.整體只用listview一個滑動控件
以上三種都是用scrollview嵌套listview。換種思維,我們知道listview裏面有addHeaderView(),addFooterView(),addView()。可以利用三個方法在合適的時候將相應部分的數據添加進去,另外listview的所有屬性都可以使用,包括重用機制。個人推薦。