實現頁面回彈滑動效果

先看下效果圖:ide

而後使用封裝好的回彈控件類,直接貼上代碼:佈局

 

  1 public class DragScrollView extends ScrollView {
  2     private static final String TAG = "TEST";
  3 
  4     // 移動因子, 是一個百分比, 好比手指移動了100px, 那麼View就只移動40px
  5     // 目的是達到一個延遲的效果
  6     private static final float MOVE_FACTOR = 0.4f;
  7 
  8     // 鬆開手指後, 界面回到正常位置須要的動畫時間
  9     private static final int ANIM_TIME = 300;
 10 
 11     // ScrollView的子View, 也是ScrollView的惟一一個子View
 12     private View contentView;
 13 
 14     // 手指按下時的Y值, 用於在移動時計算移動距離
 15     // 若是按下時不能上拉和下拉, 會在手指移動時更新爲當前手指的Y值
 16     private float startY;
 17 
 18     // 用於記錄正常的佈局位置
 19     private Rect originalRect = new Rect();
 20 
 21     // 手指按下時記錄是否能夠繼續下拉
 22     private boolean canPullDown = false;
 23 
 24     // 手指按下時記錄是否能夠繼續上拉
 25     private boolean canPullUp = false;
 26 
 27     // 在手指滑動的過程當中記錄是否移動了佈局
 28     private boolean isMoved = false;
 29 
 30     public DragScrollView(Context context) {
 31         super(context);
 32     }
 33 
 34     public DragScrollView(Context context, AttributeSet attrs) {
 35         super(context, attrs);
 36     }
 37 
 38     @Override
 39     protected void onFinishInflate() {
 40         super.onFinishInflate();
 41         if (getChildCount() > 0) {
 42             contentView = getChildAt(0);
 43         }
 44     }
 45 
 46     @Override
 47     protected void onLayout(boolean changed, int l, int t, int r, int b) {
 48         super.onLayout(changed, l, t, r, b);
 49 
 50         if (contentView == null)
 51             return;
 52 
 53         // ScrollView中的惟一子控件的位置信息, 這個位置信息在整個控件的生命週期中保持不變
 54         originalRect.set(contentView.getLeft(), contentView.getTop(), contentView.getRight(), contentView.getBottom());
 55     }
 56 
 57     /**
 58      * 在觸摸事件中, 處理上拉和下拉的邏輯
 59      */
 60     @Override
 61     public boolean dispatchTouchEvent(MotionEvent ev) {
 62 
 63         if (contentView == null) {
 64             return super.dispatchTouchEvent(ev);
 65         }
 66 
 67         int action = ev.getAction();
 68 
 69         switch (action) {
 70             case MotionEvent.ACTION_DOWN:
 71 
 72                 // 判斷是否能夠上拉和下拉
 73                 canPullDown = isCanPullDown();
 74                 canPullUp = isCanPullUp();
 75 
 76                 // 記錄按下時的Y值
 77                 startY = ev.getY();
 78                 break;
 79 
 80             case MotionEvent.ACTION_UP:
 81 
 82                 if (!isMoved)
 83                     break; // 若是沒有移動佈局, 則跳過執行
 84 
 85                 // 開啓動畫
 86                 TranslateAnimation anim = new TranslateAnimation(0, 0, contentView.getTop(), originalRect.top);
 87                 anim.setDuration(ANIM_TIME);
 88 
 89                 contentView.startAnimation(anim);
 90 
 91                 // 設置回到正常的佈局位置
 92                 contentView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom);
 93 
 94                 // 將標誌位設回false
 95                 canPullDown = false;
 96                 canPullUp = false;
 97                 isMoved = false;
 98 
 99                 break;
100             case MotionEvent.ACTION_MOVE:
101 
102                 // 在移動的過程當中, 既沒有滾動到能夠上拉的程度, 也沒有滾動到能夠下拉的程度
103                 if (!canPullDown && !canPullUp) {
104                     startY = ev.getY();
105                     canPullDown = isCanPullDown();
106                     canPullUp = isCanPullUp();
107 
108                     break;
109                 }
110 
111                 // 計算手指移動的距離
112                 float nowY = ev.getY();
113                 int deltaY = (int) (nowY - startY);
114 
115                 // 是否應該移動佈局
116                 boolean shouldMove = (canPullDown && deltaY > 0) // 能夠下拉, 而且手指向下移動
117                         || (canPullUp && deltaY < 0) // 能夠上拉, 而且手指向上移動
118                         || (canPullUp && canPullDown); // 既能夠上拉也能夠下拉(這種狀況出如今ScrollView包裹的控件比ScrollView還小)
119 
120                 if (shouldMove) {
121                     // 計算偏移量
122                     int offset = (int) (deltaY * MOVE_FACTOR);
123 
124                     // 隨着手指的移動而移動佈局
125                     contentView.layout(originalRect.left, originalRect.top + offset, originalRect.right,
126                             originalRect.bottom + offset);
127 
128                     isMoved = true; // 記錄移動了佈局
129                 }
130 
131                 break;
132             default:
133                 break;
134         }
135 
136         return super.dispatchTouchEvent(ev);
137     }
138 
139     /**
140      * 判斷是否滾動到頂部
141      */
142     private boolean isCanPullDown() {
143         return getScrollY() == 0 || contentView.getHeight() < getHeight() + getScrollY();
144     }
145 
146     /**
147      * 判斷是否滾動到底部
148      */
149     private boolean isCanPullUp() {
150         return contentView.getHeight() <= getHeight() + getScrollY();
151     }
152 }

最後就是使用方法,直接在寫好的xml中套上,就跟使用ScrollView的方法同樣。動畫

相關文章
相關標籤/搜索