前天在工做中遇到在ListView中的Item須要用ListView來展示處理後的內容,而後就遇到了一個很頭疼的問題,做爲Item的ListView無法進行滑動,並且顯示也不正常,只是顯示幾個子Item。不能將子Item所有顯示,緣由是在控件繪製出來以前要對ListView的大小進行計算,要解決將子ListView所有顯示出來的問題,就是從新計算一下其大小告知系統便可。後面這個問題比較好解決,網上已經給出解決方案: html
前輩們給出了一個方法,從新計算子ListView的大小,而後在設置本ListView的Adapter以後運行這個方法就行了,具體代碼以下: java
/** * 設置Listview的高度 */ public void setListViewHeight(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); }
可是這個方法設置的item的Layout必須是帶有onMeasure()方法的控件,不然在計算的時候會報錯,建議使用LinearLayout。 android
再一個思路相同,可是,不是額外作方法來實現onMeasure()方法的計算LIstView的大小,而是本身繼承ListView,重寫ListView的onMeasure()方法,來本身計算ListView的高度,而後再xml中直接使用這個自定義的ListView就能夠了。 ide
public class MyListView extends ListView { public MyListView (Context context, AttributeSet attrs) { super(context, attrs); } public MyListView (Context context) { super(context); } public MyListView (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }
這是解決讓做爲Item的ListView顯示所有內容的方案,可是有些時候咱們是想讓做爲Item的ListView不用所有顯示,而是能夠進行滑動,要解決這個問題就須要瞭解一下android對事件的分發機制了 性能
個人解決方案是集成ListView,重寫interceptTouchEvent使其返回false來取消父ListView對觸摸事件的攔截,將觸摸事件分發到子View來處理。而後在使用的時候,將其做爲父ListView使用,就可使子ListView能夠滑動了。思想來源於下面連接的6樓 this
http://www.eoeandroid.com/thread-3597-1-1.html 編碼
具體自定義父ListView代碼 :
public class ParentListView extends ListView { public ParentListView(Context context) { super(context); // TODO Auto-generated constructor stub } public ParentListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public ParentListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } //將 onInterceptTouchEvent的返回值設置爲false,取消其對觸摸事件的處理,將事件分發給子view @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub return false; } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <!-- 這裏作demo用,直接使用了android中的ListActivity--> <i.test.ParentListView android:id=" @android :id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:dividerHeight="2dip" android:scrollbars="none" /> </LinearLayout>
public class ListviewActivity extends ListActivity { /** Called when the activity is first created. */ private ListView mLv;//這個ListView就是自定義的View private ParentAdapter adapter; private final static String[] array = new String[]{"1","2","3","4","5","6","7","8","9","10","11","12","13","14"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mLv = getListView(); adapter = new ParentAdapter(); mLv.setAdapter(adapter); } private class ParentAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return Array.getLength(array); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return array[position]; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View view; if(position == 5){ view = View.inflate(getApplicationContext(), R.layout.item, null); ListView lv = (ListView) view.findViewById(R.id.lv); ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(ListviewActivity.this, android.R.layout.simple_list_item_1, new String[]{"a","b", "c","d","e","f","g"}); lv.setAdapter(mAdapter); } else{ TextView tv = new TextView(getApplicationContext()); tv.setText(array[position]); tv.setTextSize(30); view = tv; } return view; } } }
上面的方法一樣適合在ScrollView中嵌套能夠滑動View的狀況。 spa
後記:2013.04.10
今天登陸oschian看到有人提到我,打開消息一看,是對這篇文字的評論,很高興我寫的東西對別人有所幫助。評論人 @jimmy.zhao ,謝謝你讓我知道,我幫助了你,這是博客寫下去的動力。 .net
這篇文字是在我畢業以後剛入職次日解決的問題,話說這個問題困擾前面的人有兩個月了,我來了以後就把這個坑讓我填,前輩說在網上找的全部方案都是已經有牛人給出解決方案。都這麼說,可是沒有一我的說解決方案是什麼,因而讓我研究了下。不能說我這篇文字是最先解決這個嵌套滑動問題的,可是如你搜一下解決滑動嵌套問題的帖子基本都在我這篇以後,先本身小驕傲下。 code
下面說說我在使用這種方法解決了這個問題以後遇到的問題(好像有點繞。。但攻城獅不怕哈),但願能引發後來人的注意:
問題出在一個月以後,根據項目需求,外面的ListView,即父ListView中的條目展現文本數字時須要加入對電話號碼和HTTP連接的識別。即:若是是手機號碼,點擊以後進入撥號盤界面。你們知道,這個很簡單,只要在TextView中設置一個簡單的屬性就行了。而後個人問題就出現,由於父ListView的觸摸事件交給了子view,若是子view中的TextView帶有這種隱式的點擊事件,就會形成父ListView的卡頓現象。並且是至關卡頓。因而在項目中,仍是使用了固定子ListView大小,直接使用系統的ListView再也不重寫父ListView的onInterceptTouchEvent事件。將展現更多,做爲加載來處理。還有一個就是在使用TextView的時候,儘可能避免使用Html.from()來讓TextView支持簡單html標籤。這個太耗性能。用MAT一看便知,很少說。但願對有時間看本文一眼的人有所幫助。
生命不息,編碼不止