android 有彈性的ScrollView 簡單實現,與處理ScrollView和ListView,GridView之間的衝突

處理ScrollView和ListView,GridView之間的衝突,android

最好的辦法就是繼承這兩個類,重寫他們的onMeasure方法便可:ide

ListView:佈局

import android.widget.ListView;

/**
 * ScrollView中嵌入ListView,讓ListView全顯示出來
 * @author John
 *
 */
public class MyListView extends ListView{

    public MyListView(android.content.Context context,android.util.AttributeSet attrs){
        super(context, attrs);
    }

    /**
     * 設置不滾動
     */
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);

    }
    
}

GridView:動畫

import android.widget.GridView;

public class MyGridView extends GridView {
    public MyGridView(android.content.Context context,
            android.util.AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 設置不滾動
     */
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);

    }

}

若是是ListView中嵌套GridView也能夠用這個辦法。簡單實用的處理了這個衝突。spa

下面是重寫ScrollView,實現有彈性的ScrollViewcode

 
/**
* 有彈性的ScrollView
* 實現下拉彈回和上拉彈回
* @author John
*/
public class OwnScroview extends ScrollView {
    
   private static final String TAG = "ElasticScrollView";
    
   //移動因子, 是一個百分比, 好比手指移動了100px, 那麼View就只移動20px
   //目的是達到一個延遲的效果
   private static final float MOVE_FACTOR = 0.4f;
    
   //鬆開手指後, 界面回到正常位置須要的動畫時間
   private static final int ANIM_TIME = 300;
    
   //ScrollView的子View, 也是ScrollView的惟一一個子View
   private View contentView; 
    
   //手指按下時的Y值, 用於在移動時計算移動距離
   //若是按下時不能上拉和下拉, 會在手指移動時更新爲當前手指的Y值
   private float startY;
    
   //用於記錄正常的佈局位置
   private Rect originalRect = new Rect();
    
   //手指按下時記錄是否能夠繼續下拉
   private boolean canPullDown = false;
    
   //手指按下時記錄是否能夠繼續上拉
   private boolean canPullUp = false;
    
   //在手指滑動的過程當中記錄是否移動了佈局
   private boolean isMoved = false;

   public OwnScroview(Context context) {
       super(context);
   }
    
   public OwnScroview(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

   @Override
   protected void onFinishInflate() {
       if (getChildCount() > 0) {
           contentView = getChildAt(0);
       }
   }
    
   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b) {
       super.onLayout(changed, l, t, r, b);
        
       if(contentView == null) return;

       //ScrollView中的惟一子控件的位置信息, 這個位置信息在整個控件的生命週期中保持不變
       originalRect.set(contentView.getLeft(), contentView.getTop(), contentView
               .getRight(), contentView.getBottom());
   }

   /**
    * 在觸摸事件中, 處理上拉和下拉的邏輯
    */
   @Override
   public boolean dispatchTouchEvent(MotionEvent ev) {
        
       if (contentView == null) {
           return super.dispatchTouchEvent(ev);
       }

       int action = ev.getAction();
        
       switch (action) {
       case MotionEvent.ACTION_DOWN:
            
           //判斷是否能夠上拉和下拉
           canPullDown = isCanPullDown();
           canPullUp = isCanPullUp();
            
           //記錄按下時的Y值
           startY = ev.getY();
           break;
            
       case MotionEvent.ACTION_UP:
            
           if(!isMoved) break;  //若是沒有移動佈局, 則跳過執行
            
           // 開啓動畫
           TranslateAnimation anim = new TranslateAnimation(0, 0, contentView.getTop(),
                   originalRect.top);
           anim.setDuration(ANIM_TIME);
            
           contentView.startAnimation(anim);
            
           // 設置回到正常的佈局位置
           contentView.layout(originalRect.left, originalRect.top, 
                   originalRect.right, originalRect.bottom);
            
           //將標誌位設回false
           canPullDown = false;
           canPullUp = false;
           isMoved = false;
            
           break;
       case MotionEvent.ACTION_MOVE:
            
           //在移動的過程當中, 既沒有滾動到能夠上拉的程度, 也沒有滾動到能夠下拉的程度
           if(!canPullDown && !canPullUp) {
               startY = ev.getY();
               canPullDown = isCanPullDown();
               canPullUp = isCanPullUp();
                
               break;
           }
            
           //計算手指移動的距離
           float nowY = ev.getY();
           int deltaY = (int) (nowY - startY);
            
           //是否應該移動佈局
           boolean shouldMove = 
                   (canPullDown && deltaY > 0)    //能夠下拉, 而且手指向下移動
                   || (canPullUp && deltaY< 0)    //能夠上拉, 而且手指向上移動
                   || (canPullUp && canPullDown); //既能夠上拉也能夠下拉(這種狀況出如今ScrollView包裹的控件比ScrollView還小)
            
           if(shouldMove){
               //計算偏移量
               int offset = (int)(deltaY * MOVE_FACTOR);
                
               //隨着手指的移動而移動佈局
               contentView.layout(originalRect.left, originalRect.top + offset,
                       originalRect.right, originalRect.bottom + offset);
                
               isMoved = true;  //記錄移動了佈局
           }
            
           break;
       default:
           break;
       }

       return super.dispatchTouchEvent(ev);
   }
    

   /**
    * 判斷是否滾動到頂部
    */
   private boolean isCanPullDown() {
       return getScrollY() == 0 || 
               contentView.getHeight() < getHeight() + getScrollY();
   }
    
   /**
    * 判斷是否滾動到底部
    */
   private boolean isCanPullUp() {
       return  contentView.getHeight() <= getHeight() + getScrollY();
   }
    
}

而後再xml中用上就好了。xml

相關文章
相關標籤/搜索