ScrollView套ListView會存以下兩個問題
1.里面的listView高度無法算出來,通常只能顯示listview的其中一行
2.listview不能滾動
這里我用的是可展開的(ExpandableListView
解決問題一,如果ExpandableListView是的子項是用寫死的布局文件來加載的,只要在設置ListView的Adapter后調用此靜態方法即可讓ListView正確的顯示在其父ListView的ListItem中。但是要注意的是,子ListView的每個Item必須是LinearLayout,不能是其他的,因為其他的Layout(如RelativeLayout)沒有重寫onMeasure(),所以會在onMeasure()時拋出異常。
1 public static void setListViewHeightBasedOnChildren(ListView listView) { 2 ListAdapter listAdapter = listView.getAdapter(); 3 if (listAdapter == null) { 4 return; 5 } 6 int totalHeight = 0; 7 for (int i = 0; i < listAdapter.getCount(); i++) { 8 View listItem = listAdapter.getView(i, null, listView); 9 listItem.measure(0, 0); 10 totalHeight += listItem.getMeasuredHeight(); 11 } 12 ViewGroup.LayoutParams params = listView.getLayoutParams(); 13 params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); 14 listView.setLayoutParams(params); 15 }
如果ExpandableListView 的子項是用代碼來代碼動態加載的,那么給每個子項定義一個高度,這個就可以計算整個listview的高度了。代碼如下:
先定義子項高度
public static final int ItemHeight = 85;
定義子項的TextView布局
1 static public TextView getTextView(Context context) { 2 AbsListView.LayoutParams lp = new AbsListView.LayoutParams( 3 ViewGroup.LayoutParams.FILL_PARENT, ItemHeight); 4 TextView textView = new TextView(context); 5 textView.setLayoutParams(lp); 6 textView.setTextColor(Color.BLACK); 7 textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); 8 return textView; 9 }
然后extends BaseExpandableListAdapter中重寫以下方法,其中getChild(groupPosition, childPosition).toString()是從數組中讀出來的要顯示在子項TextView中的文字。
1 @Override 2 public View getChildView(int groupPosition, int childPosition, 3 boolean isLastChild, View convertView, ViewGroup parent) { 4 TextView textView = getTextView(this.parentContext); 5 textView.setText(getChild(groupPosition, childPosition).toString()); 6 textView.setPadding(myPaddingLeft + PaddingLeft, 0, 0, 0); 7 return textView; 8 }
這樣,問題一就解決了。
問題二就是ScrollView中嵌套listView后ListView不能進行滑動,只能看到顯示出來的ListView一部分,解決辦法原理很簡單ScrollView有一個方法requestDisallowInterceptTouchEvent(boolean);這個方法是設置是否交出ontouch權限的,如果讓外層的scrollview.requestDisallowInterceptTouchEvent(false);那么外層的onTouch權限會失去,這樣里面的listview就能拿到ontouch權限了,listView就能滾動了。
問題是:權限只有一個,要支持兩個view都能滾動。監聽OnTouch的MotionEvent.ACTION_SCROLL:事件當手指觸到listview的時候,讓外面的scrollview交出權限,當手指觸碰到listview之外的時候,讓外面的scrollview重新獲得權限。這樣ok了。R.id.hlpg_main_lv:是listview對應的id,R.id.hlpg_main_allcontent:是listview之外的布局的id。
且看代碼實現:
1 case R.id.hlpg_main_lv: 2 sView.requestDisallowInterceptTouchEvent(false); 3 break; 4 case R.id.hlpg_main_allcontent: 5 sView.requestDisallowInterceptTouchEvent(true); 6 break; 7 default: 8 sView.requestDisallowInterceptTouchEvent(true); 9 break; 10
這樣之后第二個問題也就解決了。
Listview中還提供了對listView滾動的監聽,設置這些監聽便可以做一些相應的操作
1 expandableListView.setOnScrollListener(new OnScrollListener() { 2 @Override 3 public void onScrollStateChanged(AbsListView view, int scrollState) { 4 switch (scrollState) { // 當不滾動時 5 case OnScrollListener.SCROLL_STATE_IDLE: 6 // TODO coding here dosometing 7 break; 8 } 9 } 10 @Override 11 public void onScroll(AbsListView view, int firstVisibleItem, 12 int visibleItemCount, int totalItemCount) { 13 // TODO coding here dosometing 14 } 15 });
這個問題是在開發過程中遇到的,最初想着用其它方式來實現,發現越做越復雜還達不到想要的效果,最后翻閱資料才發現可以來切換ScrollView和ListView之間的OnTouch焦點實現嵌套滑動,希望這個技術分享解決大家遇到的同類問題