1. 程式人生 > >自定義ScrollView 實現上拉下拉的回彈效果--並且子控件中有Viewpager的情況

自定義ScrollView 實現上拉下拉的回彈效果--並且子控件中有Viewpager的情況

是否 AS abs pri tar utils lda animation ted

技術分享圖片

onInterceptTouchEvent就是對子控件中Viewpager的處理:左右滑動應該讓viewpager消費

  1 public class MyScrollView extends ScrollView {
  2 
  3     private View childView;
  4 
  5     public MyScrollView(Context context) {
  6         super(context);
  7     }
  8 
  9     public MyScrollView(Context context, AttributeSet attrs) {
10 super(context, attrs); 11 } 12 13 public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 14 super(context, attrs, defStyleAttr); 15 } 16 17 // @Override 18 // protected void onLayout(boolean changed, int l, int t, int r, int b) { 19 // super.onLayout(changed, l, t, r, b);
20 // } 21 22 //獲取子視圖 23 @Override 24 protected void onFinishInflate() { 25 super.onFinishInflate(); 26 if (getChildCount() > 0) { 27 childView = getChildAt(0); 28 } 29 } 30 31 private int lastY;//上一次y軸方向操作的坐標位置 32 private Rect normal = new
Rect();//用於記錄臨界狀態的左、上、右、下 33 private boolean isFinishAnimation = true;//是否動畫結束 34 35 private int lastX, downX, downY; 36 37 //攔截:實現父視圖對子視圖的攔截 38 //是否攔截成功,取決於方法的返回值。返回值true:攔截成功。反之,攔截失敗 39 @Override 40 public boolean onInterceptTouchEvent(MotionEvent ev) { 41 boolean isIntercept = false; 42 int eventX = (int) ev.getX(); 43 int eventY = (int) ev.getY(); 44 switch (ev.getAction()) { 45 case MotionEvent.ACTION_DOWN: 46 lastX = downX = eventX; 47 lastY = downY = eventY; 48 break; 49 case MotionEvent.ACTION_MOVE: 50 //獲取水平和垂直方向的移動距離 51 int absX = Math.abs(eventX - downX); 52 int absY = Math.abs(eventY - downY); 53 54 if(absY > absX && absY >= UIUtils.dp2px(10)){ 55 isIntercept = true;//執行攔截 56 } 57 58 lastX = eventX; 59 lastY = eventY; 60 break; 61 } 62 63 return isIntercept; 64 } 65 66 @Override 67 public boolean onTouchEvent(MotionEvent ev) { 68 if (childView == null || !isFinishAnimation) { 69 return super.onTouchEvent(ev); 70 } 71 72 int eventY = (int) ev.getY();//獲取當前的y軸坐標 73 switch (ev.getAction()) { 74 case MotionEvent.ACTION_DOWN: 75 lastY = eventY; 76 break; 77 case MotionEvent.ACTION_MOVE: 78 79 int dy = eventY - lastY;//微小的移動量 80 81 if (isNeedMove()) { 82 if (normal.isEmpty()) { 83 //記錄了childView的臨界狀態的左、上、右、下 84 normal.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom()); 85 86 } 87 //重新布局 88 childView.layout(childView.getLeft(), childView.getTop() + dy / 2, childView.getRight(), childView.getBottom() + dy / 2); 89 } 90 91 lastY = eventY;//重新賦值 92 break; 93 case MotionEvent.ACTION_UP: 94 if (isNeedAnimation()) { 95 //使用平移動畫 96 int translateY = childView.getBottom() - normal.bottom; 97 TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, -translateY); 98 translateAnimation.setDuration(200); 99 // translateAnimation.setFillAfter(true);//停留在最終位置上 100 101 translateAnimation.setAnimationListener(new Animation.AnimationListener() { 102 @Override 103 public void onAnimationStart(Animation animation) { 104 isFinishAnimation = false; 105 } 106 107 @Override 108 public void onAnimationEnd(Animation animation) { 109 isFinishAnimation = true; 110 childView.clearAnimation();//清除動畫 111 //重新布局 112 childView.layout(normal.left, normal.top, normal.right, normal.bottom); 113 //清除normal的數據 114 normal.setEmpty(); 115 } 116 117 @Override 118 public void onAnimationRepeat(Animation animation) { 119 120 } 121 }); 122 123 //啟動動畫 124 childView.startAnimation(translateAnimation); 125 } 126 127 128 break; 129 } 130 131 132 return super.onTouchEvent(ev); 133 } 134 135 //判斷是否需要執行平移動畫 136 private boolean isNeedAnimation() { 137 return !normal.isEmpty(); 138 139 } 140 141 private boolean isNeedMove() { 142 int childMeasuredHeight = childView.getMeasuredHeight();//獲取子視圖的高度 143 int scrollViewMeasuredHeight = this.getMeasuredHeight();//獲取布局的高度 144 145 Log.e("TAG", "childMeasuredHeight = " + childMeasuredHeight); 146 Log.e("TAG", "scrollViewMeasuredHeight = " + scrollViewMeasuredHeight); 147 148 int dy = childMeasuredHeight - scrollViewMeasuredHeight;//dy >= 0 149 150 int scrollY = this.getScrollY();//獲取用戶在y軸方向上的偏移量 (上 + 下 -) 151 if (scrollY <= 0 || scrollY >= dy) { 152 return true;//按照我們自定義的MyScrollView的方式處理 153 } 154 //其他處在臨界範圍內的,返回false。即表示,仍按照ScrollView的方式處理 155 return false; 156 } 157 }

自定義ScrollView 實現上拉下拉的回彈效果--並且子控件中有Viewpager的情況