如果很平常的兩個listview組件豎直放在linearLayout布局中,結果是:
兩個listview 很獨立,中間似乎有個分割線,完全吧他們分離了,各自獨立滾動,如果上面的listview把整個屏幕占據了,那么下面的listview永遠滾不上來了,看不到了。
網上關於這個話題大約有兩種方法解決:
(1)有多少個listview就用多少個listview組件,然后放在一個LinearLayout布局里面,linearLayout布局在放入Scrollview中。
這樣做,必須先計算出每個listview被對應的adapter適配之后的實際高度,然后設置listview為這個高度。再放入scrollview中ok了。
(2)不管有多少個listview,都放在一個listview,用一個adapter適配,在listview組件對應的數據存儲結構list中,設置flag標志位,在adapter中再對不同的flag做不同的適配。
一開始,項目中使用的第一種方法,隨着項目的進行,發現第一種方法會在很多種情況下不適應,最嚴重的問題,就是第一種方法非常耗時,已經到了一種無可忍受的地步了。
一個很常見的例子,城市列表,有兩個list:熱門城市、全部城市

假如用第一種方法,先計算兩個listview在對應的adapter適配后的高度:
public static void setListViewHeightBasedOnChildren(ListView listView) { 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); }
其實從這段代碼中,和上面這個需求,問題已經可以看出來了。
adapter有一個方法getView,這個方法是如果這個listview的某行將要在屏幕上顯示了,系統就會自動調用getview得到這個布局,然后顯示。
也就是每次被調用的次數,只是屏幕上能顯示的條數,最多也就是10條左右。
而一次計算高度就要對每一條調用getview,for循環里面:
View listItem = listAdapter.getView(i, null, listView);
是非常耗時的,尤其對於全部城市,幾百條,3~4秒肯定是要的。所以面對這個需求,第一種方法是不可行。
除了耗時,第一種方法,維護性也不好。就比如,一個頁面中,listview的數據是不定的,是動態計算得到的。用第一種方法分散到多個listview,對於一些事件監聽,不好操作。
下面講解下第二種方法的具體實現
拿上面城市列表具體
分兩塊:
1、數據dataList
2、adapter
1、datalist填充:
主要以一個flag標記,對於城市列表共有兩種布局:
一個是頭信息

一個是具體的城市

代碼:
cityList.clear(); Map<String, Object> map1 = new HashMap<String, Object>(); map1.put("city", new City(0, "熱門城市", '#')); cityList.add(map1); List<City> cities = getHotCity(); for (City city : cities) { Map<String, Object> map = new HashMap<String, Object>(); map.put("is_selected", false); map.put("city", city); cityList.add(map); } Map<String, Object> map2 = new HashMap<String, Object>(); map2.put("city", new City(0, "全部城市", '$')); cityList.add(map2); index++; cities = getAllCity(); for (City city : cities) { Map<String, Object> map = new HashMap<String, Object>(); map.put("is_selected", false); map.put("city", city); cityList.add(map); }
哦~這個好像沒用到flag標記,直接判斷city的name了~~~
2、adapter適配:
@Override public View getView(final int position, View convertView, ViewGroup parent) { City city = (City) listData.get(position).get("city"); String nameString = city.getName(); if (nameString.compareTo("熱門城市") == 0) { convertView = mInflater.inflate(headResource, null); ((TextView) convertView.findViewById(R.id.label)).setText("熱門城市"); return convertView; } if (nameString.compareTo("全部城市") == 0) { convertView = mInflater.inflate(headResource, null); ((TextView) convertView.findViewById(R.id.label)).setText("全部城市"); return convertView; } convertView = mInflater.inflate(listResource, null); ((TextView) convertView.findViewById(R.id.label)).setText(nameString); ImageView isSelectedImageView = (ImageView) convertView.findViewById(R.id.is_selected); // boolean isSelected = (Boolean) listData.get(position).get("is_selected"); int whichIsSelected = (Integer) listData.get(getCount() - 1).get("which_is_selected"); if (city.getId() == whichIsSelected) isSelectedImageView.setBackgroundResource(R.drawable.is_selected_yes); else isSelectedImageView.setBackgroundResource(R.drawable.is_selected_no); return convertView; }
對於各行的點擊操作也可以根據flag統一處理。維護起來非常方便。
