Android 在ListView中嵌套ListView的事件處理


 前天在工作中遇到在ListView中的Item需要用ListView來展現處理后的內容,然后就遇到了一個很頭疼的問題,作為Item的ListView沒法進行滑動,而且顯示也不正常,只是顯示幾個子Item。不能將子Item全部顯示,原因是在控件繪制出來之前要對ListView的大小進行計算,要解決將子ListView全部顯示出來的問題,就是重新計算一下其大小告知系統即可。后面這個問題比較好解決,網上已經給出解決方案:

前輩們給出了一個方法,重新計算子ListView的大小,然后在設置本ListView的Adapter之后運行這個方法就好了,具體代碼如下:

/** 

     * 設置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

 

再一個思路相同,但是,不是額外做方法來實現onMeasure()方法的計算LIstView的大小,而是自己繼承ListView,重寫ListView的onMeasure()方法,來自己計算ListView的高度,然后再xml中直接使用這個自定義的ListView就可以了。

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樓

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文件:
<?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>
 
        

activity代碼如下:

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的情況。

后記:2013.04.10
今天登錄oschian看到有人提到我,打開消息一看,是對這篇文字的評論,很高興我寫的東西對別人有所幫助。評論人 @jimmy.zhao ,謝謝你讓我知道,我幫助了你,這是博客寫下去的動力。

這篇文字是在我畢業之后剛入職第二天解決的問題,話說這個問題困擾前面的人有兩個月了,我來了之后就把這個坑讓我填,前輩說在網上找的所有方案都是已經有牛人給出解決方案。都這么說,但是沒有一個人說解決方案是什么,於是讓我研究了下。不能說我這篇文字是最早解決這個嵌套滑動問題的,但是如你搜一下解決滑動嵌套問題的帖子基本都在我這篇之后,先自己小驕傲下。

下面說說我在使用這種方法解決了這個問題之后遇到的問題(好像有點繞。。但攻城獅不怕哈),希望能引起后來人的注意:
問題出在一個月之后,根據項目需求,外面的ListView,即父ListView中的條目展示文本數字時需要加入對電話號碼和HTTP鏈接的識別。即:如果是手機號碼,點擊之后進入撥號盤界面。大家知道,這個很簡單,只要在TextView中設置一個簡單的屬性就好了。然后我的問題就出現,因為父ListView的觸摸事件交給了子view,如果子view中的TextView帶有這種隱式的點擊事件,就會造成父ListView的卡頓現象。而且是相當卡頓。於是在項目中,還是使用了固定子ListView大小,直接使用系統的ListView不再重寫父ListView的onInterceptTouchEvent事件。將展示更多,作為加載來處理。還有一個就是在使用TextView的時候,盡量避免使用Html.from()來讓TextView支持簡單html標簽。這個太耗性能。用MAT一看便知,不多說。希望對有時間看本文一眼的人有所幫助。

轉自http://my.oschina.net/zhibuji/blog/70892

 

 

/**
02  
03      * 設置Listview的高度
04  
05      */ 
06  
07     public voidsetListViewHeight(ListView listView) {  
08  
09         ListAdapter listAdapter = listView.getAdapter();   
10  
11         if(listAdapter == null) {  
12  
13             return;  
14  
15         }  
16  
17         inttotalHeight = 0;  
18  
19         for (inti = 0; i < listAdapter.getCount(); i++) {  
20  
21             View listItem = listAdapter.getView(i, null, listView);  
22  
23             listItem.measure(00);  
24  
25             totalHeight += listItem.getMeasuredHeight();  
26  
27         }  
28  
29         ViewGroup.LayoutParams params = listView.getLayoutParams();  
30  
31         params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));  
32  
33         listView.setLayoutParams(params); 
34  
35     }

 

 

但是這個方法設置的item的Layout必須是帶有onMeasure()方法的控件,否則在計算的時候會報錯,建議使用LinearLayout

再一個思路相同,但是,不是額外做方法來實現onMeasure()方法的計算LIstView的大小,而是自己繼承ListView,重寫ListView的onMeasure()方法,來自己計算ListView的高度,然后再xml中直接使用這個自定義的ListView就可以了。

 

01 public class MyListView extendsListView {
02  
03     public MyListView  (Context context, AttributeSet attrs) {
04  
05         super(context, attrs);
06  
07     }
08  
09     public MyListView  (Context context) {
10  
11         super(context);
12  
13     }
14  
15     public  MyListView  (Context context, AttributeSet attrs, intdefStyle) {
16  
17         super(context, attrs, defStyle);
18  
19     }
20  
21     @Override
22  
23     public void onMeasure(int widthMeasureSpec, intheightMeasureSpec) {
24  
25         intexpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
26  
27                 MeasureSpec.AT_MOST);
28  
29         super.onMeasure(widthMeasureSpec, expandSpec);
30  
31     }
32  
33 }

 

 

這是解決讓作為Item的ListView顯示全部內容的方案,但是有些時候我們是想讓作為Item的ListView不用全部顯示,而是可以進行滑動,要解決這個問題就需要了解一下Android對事件的分發機制了

我的解決方案是集成ListView,重寫interceptTouchEvent使其返回false來取消父ListView對觸摸事件的攔截,將觸摸事件分發到子View來處理。然后在使用的時候,將其作為父ListView使用,就可以使子ListView可以滑動了。思想來源於下面鏈接的6樓

http://www.eoeandroid.com/thread-3597-1-1.html

 

具體自定義父ListView代碼 : 

 

01 public class ParentListView extends ListView {
02  
03 public ParentListView(Context context) {
04  
05 super(context);
06  
07 // TODO Auto-generated constructor stub
08  
09 }
10  
11 public ParentListView(Context context, AttributeSet attrs, int defStyle) {
12  
13 super(context, attrs, defStyle);
14  
15 // TODO Auto-generated constructor stub
16  
17 }
18  
19 public ParentListView(Context context, AttributeSet attrs) {
20  
21 super(context, attrs);
22  
23 // TODO Auto-generated constructor stub
24  
25 }
26 //將 onInterceptTouchEvent的返回值設置為false,取消其對觸摸事件的處理,將事件分發給子view
27  
28 @Override
29  
30 public boolean onInterceptTouchEvent(MotionEvent ev) {
31  
32 // TODO Auto-generated method stub
33  
34 return false;
35  
36 }
37  
38 }

 

 

xml文件:
01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:layout_width="fill_parent"
04     android:layout_height="fill_parent"
05     android:orientation="vertical" >
06 <!-- 這里做demo用,直接使用了android中的ListActivity-->
07     <i.test.ParentListView android:id=" @android :id/list"
08         android:layout_width="fill_parent"
09         android:layout_height="fill_parent"
10         android:dividerHeight="2dip"
11         android:scrollbars="none"
12         />
13  
14 </LinearLayout>
 
 
activity代碼如下:
01 public class ListviewActivity extends ListActivity {
02     /** Called when the activity is first created. */
03 private ListView mLv;//這個ListView就是自定義的View
04 private ParentAdapter adapter;
05 private final static String[] array = newString[]{"1","2","3","4","5","6","7","8","9","10","11","12","13","14"};
06     @Override
07     public void onCreate(Bundle savedInstanceState) {
08         super.onCreate(savedInstanceState);
09         setContentView(R.layout.main);
10         mLv = getListView();
11         adapter = new ParentAdapter();
12         mLv.setAdapter(adapter);
13          
14     }
15     private class ParentAdapter extends BaseAdapter{
16  
17 @Override
18 public int getCount() {
19 // TODO Auto-generated method stub
20 return Array.getLength(array);
21 }
22  
23 @Override
24 public Object getItem(int position) {
25 // TODO Auto-generated method stub
26 return array[position];
27 }
28  
29 @Override
30 public long getItemId(int position) {
31 // TODO Auto-generated method stub
32 return position;
33 }
34  
35 @Override
36 public View getView(int position, View convertView, ViewGroup parent) {
37 // TODO Auto-generated method stub
38 View view;
39 if(position == 5){
40 view = View.inflate(getApplicationContext(), R.layout.item, null);
41 ListView lv = (ListView) view.findViewById(R.id.lv);
42 ArrayAdapter<String> mAdapter = newArrayAdapter<String>(ListviewActivity.this, android.R.layout.simple_list_item_1, newString[]{"a","b",
43 "c","d","e","f","g"});
44 lv.setAdapter(mAdapter);
45 }
46 else{
47 TextView  tv = new TextView(getApplicationContext());
48 tv.setText(array[position]);
49 tv.setTextSize(30);
50 view = tv;
51 }
52 return view;
53 }
54     
55     }
56 }
 

上面的方法同樣適合在ScrollView中嵌套可以滑動View的情況。

 

轉自http://my.oschina.net/zhibuji/blog/70892

 
3


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM