Android開發之scrollview嵌套listview相關佈局的解析

過兩天同學要回家相親結婚去了,昨晚作爲送行之聚,喝的是稀里嘩啦。早上起來喝了一杯牛奶後卻無所事事,所以乾脆把前幾天做項目時總結的一些知識梳理一下。

其實標題與本文不算太相符,這裏借標題引申出一個特殊的佈局,進而再去挖掘這種佈局的解決思路。這種佈局很常見,拿美團首頁來說,頂部是一些雜七麻八的佈局顯示一些分類模塊和熱門頻道之類的,中間是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的所有屬性都可以使用,包括重用機制。個人推薦。


發佈了36 篇原創文章 · 獲贊 37 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章