1. 程式人生 > >ScrollView巢狀ListView,GridView,ViewPager,以及這些控制元件自動滾動到底部問題的解決

ScrollView巢狀ListView,GridView,ViewPager,以及這些控制元件自動滾動到底部問題的解決

Google是不推薦在ScrollView 中放入一個可滾動的選單的,比如放置一個ListView、GridView、ViewPager這些控制元件的,儘量不要讓兩者巢狀,但有時候還是有這個需求,先不管它合不合理。如果直接在ScrollView中巢狀只會出現一行,然後在其中滾動,這樣不是很好,下面是我的整理,希望對大家有幫助,我也是從網上摘抄的,當然加入了一些我自己的東西。

一、在ScrollView中巢狀ListView,有兩張方法

第一種是自定義View,繼承ListView程式碼如下:

  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.widget.ListView;  
  4. publicclass MyListView extends ListView {  
  5.     public MyListView(Context context) {  
  6.         super(context);  
  7.     }  
  8.     public MyListView(Context context, AttributeSet attrs, int defStyle) {  
  9.         super(context, attrs, defStyle);  
  10.     }  
  11.     public MyListView(Context context, AttributeSet attrs) {  
  12.         super(context, attrs);  
  13.     }  
  14.     @Override
  15.     protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  16.          int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,    
  17.                  MeasureSpec.AT_MOST);      
  18.         super.onMeasure(widthMeasureSpec, expandSpec);  
  19.     }  
  20. }  
第二種
  1. import android.view.View;  
  2. import android.view.ViewGroup;  
  3. import android.widget.ListAdapter;  
  4. import android.widget.ListView;  
  5. publicclass Utility {  
  6.     publicstaticvoid setListViewHeightBasedOnChildren(ListView listView) {  
  7.         ListAdapter listAdapter = listView.getAdapter();  
  8.         if (listAdapter == null) {  
  9.             // pre-condition
  10.             return;  
  11.         }  
  12.         int totalHeight = 0;  
  13.         for (int i = 0; i < listAdapter.getCount(); i++) {  
  14.             View listItem = listAdapter.getView(i, null, listView);  
  15.             listItem.measure(00);  
  16.             totalHeight += listItem.getMeasuredHeight();  
  17.         }  
  18.         ViewGroup.LayoutParams params = listView.getLayoutParams();  
  19.         params.height = totalHeight  
  20.                 + (listView.getDividerHeight() * (listAdapter.getCount() - 1));  
  21.         listView.setLayoutParams(params);  
  22.     }  
  23. }  

第二種在setAdapter之後呼叫Utility.setListViewHeightBasedOnChildren(listview)這個方法,有些資料說只能item的根佈局要LinearLayout,但是我的跟佈局為RelativeLayout也可以的。

這兩種都可以,但是在有些情況下中能用第一種,比如你顯示ListView是一個ListFragment就只能用第二種方法了。

二、在ScrollView中巢狀GridView

  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.widget.GridView;  
  4. publicclass NoScrollGridView extends GridView {    
  5.     public NoScrollGridView(Context context) {    
  6.         super(context);    
  7.     }    
  8.     public NoScrollGridView(Context context, AttributeSet attrs) {    
  9.         super(context, attrs);    
  10.     }    
  11.     @Override
  12.     protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    
  13.         int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);    
  14.         super.onMeasure(widthMeasureSpec, expandSpec);    
  15.     }    
  16. }    
二、在ScrollView中巢狀ViewPager,也有兩張方法
第一種自定義ScrollView
  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.view.MotionEvent;  
  4. import android.widget.ScrollView;  
  5. /** 
  6.  * 能夠相容ViewPager的ScrollView 
  7.  *  
  8.  * @Description: 解決了ViewPager在ScrollView中的滑動反彈問題 
  9.  */
  10. publicclass ScrollViewExtend extends ScrollView {  
  11.     // 滑動距離及座標
  12.     privatefloat xDistance, yDistance, xLast, yLast;  
  13.     public ScrollViewExtend(Context context, AttributeSet attrs) {  
  14.         super(context, attrs);  
  15.     }  
  16.     @Override
  17.     publicboolean onInterceptTouchEvent(MotionEvent ev) {  
  18.         switch (ev.getAction()) {  
  19.         case MotionEvent.ACTION_DOWN:  
  20.             xDistance = yDistance = 0f;  
  21.             xLast = ev.getX();  
  22.             yLast = ev.getY();  
  23.             break;  
  24.         case MotionEvent.ACTION_MOVE:  
  25.             finalfloat curX = ev.getX();  
  26.             finalfloat curY = ev.getY();  
  27.             xDistance += Math.abs(curX - xLast);  
  28.             yDistance += Math.abs(curY - yLast);  
  29.             xLast = curX;  
  30.             yLast = curY;  
  31.             if (xDistance > yDistance) {  
  32.                 returnfalse;  
  33.             }  
  34.         }  
  35.         returnsuper.onInterceptTouchEvent(ev);  
  36.     }  
  37. }  
第二種是自定義ViewPager
  1. import android.content.Context;  
  2. import android.graphics.PointF;  
  3. import android.support.v4.view.ViewPager;  
  4. import android.util.AttributeSet;  
  5. import android.view.MotionEvent;  
  6. /** 
  7.  * 巢狀在ScrollView中的ViewPager,解決衝突 
  8.  * @author m3 
  9.  * 
  10.  */
  11. publicclass ChildViewPager extends ViewPager {  
  12.     /** 觸控時按下的點 **/
  13.     PointF downP = new PointF();  
  14.     /** 觸控時當前的點 **/
  15.     PointF curP = new PointF();  
  16.     OnSingleTouchListener onSingleTouchListener;  
  17.     public ChildViewPager(Context context, AttributeSet attrs) {  
  18.         super(context, attrs);  
  19.         // TODO Auto-generated constructor stub
  20.     }  
  21.     public ChildViewPager(Context context) {  
  22.         super(context);  
  23.         // TODO Auto-generated constructor stub
  24.     }  
  25.     @Override
  26.     publicboolean onInterceptTouchEvent(MotionEvent arg0) {  
  27.         // TODO Auto-generated method stub
  28.         // 當攔截觸控事件到達此位置的時候,返回true,
  29.         // 說明將onTouch攔截在此控制元件,進而執行此控制元件的onTouchEvent
  30.         returntrue;  
  31.     }  
  32.     @Override
  33.     publicboolean onTouchEvent(MotionEvent arg0) {  
  34.         // TODO Auto-generated method stub
  35.         // 每次進行onTouch事件都記錄當前的按下的座標
  36.         curP.x = arg0.getX();  
  37.         curP.y = arg0.getY();  
  38.         if (arg0.getAction() == MotionEvent.ACTION_DOWN) {  
  39.             // 記錄按下時候的座標
  40.             // 切記不可用 downP = curP ,這樣在改變curP的時候,downP也會改變
  41.             downP.x = arg0.getX();  
  42.             downP.y = arg0.getY();  
  43.             // 此句程式碼是為了通知他的父ViewPager現在進行的是本控制元件的操作,不要對我的操作進行干擾
  44.             getParent().requestDisallowInterceptTouchEvent(true);  
  45.         }  
  46.         if (arg0.getAction() == MotionEvent.ACTION_MOVE) {  
  47.             // 此句程式碼是為了通知他的父ViewPager現在進行的是本控制元件的操作,不要對我的操作進行干擾
  48.             getParent().requestDisallowInterceptTouchEvent(true);  
  49.         }  
  50.         if (arg0.getAction() == MotionEvent.ACTION_UP) {  
  51.             // 在up時判斷是否按下和鬆手的座標為一個點
  52.             // 如果是一個點,將執行點選事件,這是我自己寫的點選事件,而不是onclick
  53.             if (downP.x == curP.x && downP.y == curP.y) {  
  54.                 onSingleTouch();  
  55.                 returntrue;  
  56.             }  
  57.         }  
  58.         returnsuper.onTouchEvent(arg0);  
  59.     }  
  60.     /** 
  61.      * 單擊 
  62.      */
  63.     publicvoid onSingleTouch() {  
  64.         if (onSingleTouchListener != null) {  
  65.             onSingleTouchListener.onSingleTouch();  
  66.         }  
  67.     }  
  68.     /** 
  69.      * 建立點選事件介面 
  70.      *  
  71.      * @author wanpg 
  72.      *  
  73.      */
  74.     publicinterface OnSingleTouchListener {  
  75.         publicvoid onSingleTouch();  
  76.     }  
  77.     publicvoid setOnSingleTouchListener(  
  78.             OnSingleTouchListener onSingleTouchListener) {  
  79.         this.onSingleTouchListener = onSingleTouchListener;  
  80.     }  
  81. }  
第二個問題在ScrollView巢狀ListView,GridView,如果這些子控制元件很長超出了螢幕的高度,那麼ScrollView會自動滾到底部,但是我們需要預設在頂部,我們要在ListView和GridView上面的view中加入,一下程式碼即可解決:
  1. view.setFocusable(true);  
  2. view.setFocusableInTouchMode(true);  
  3. view.requestFocus();