安卓笔记侠

专注安卓开发

导航

自定义ScrollView 实现上拉下拉的回弹效果--并且子控件中有Viewpager的情况

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 }

 

posted on 2018-05-01 20:19  安卓笔记侠  阅读(1287)  评论(0编辑  收藏  举报