Scrollview 回弹效果自定义控件

2,631 阅读7分钟
原文链接: www.cnblogs.com
滚动回弹效果分析: 首先,创建一个类,继承scrollview,重写ontouch事件,实现伸缩回弹效果。 scroollview节点下只能有一个子节点,这个子节点就是我们要移动的view布局。   第一步:获取要操作的子view布局 第二步:重写onTouch事件监听     分析具体事件: 观察分析得出结论: 让布局移动每一次拉动的Y轴一半的距离,然后松手滚动[携带动画]回到原来的位置。 下拉或者上拉的时候,记录按下时的Y轴位置 action_down   移动过程中的处理: 计算上一次与本次的Y轴(拉动距离)[而不是按下时候的Y值,和现在移动到的Y值,是每上一次和本次的Y值比较 判断是否需要移动布局的情况:Y轴的一个距离偏移   //2种情况,随着布局的拖动, inner.getMeasuredHeight()的值是变化的 //inner.getMeasuredHeight()与getHeight()的区别: 当屏幕可以包裹内容的时候,他们的值相等 当view的高度超出屏幕时,getMeasuredHeight()是实际View的大小,与屏幕无关,getHeight的大小此时则是屏幕的大小。 此时,getMeasuredHeight() = getHeight+超出部分。   抬起的处理:布局回滚到正常位置 移动动画回滚到正常位置(*:动画执行期间,不允许拖拉操作)    距离:-的滚动距离 ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 public class MyScrollview extends ScrollView {       //要操作的布局     private View innerView;     private float y;     private Rect normal = new Rect();     private boolean animationFinish = true ;       public MyScrollview(Context context) {         super(context, null );     }       public MyScrollview(Context context, AttributeSet attrs) {         super(context, attrs);     }       public MyScrollview(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }       @Override     protected void onFinishInflate() {         int childCount = getChildCount();         if (childCount > 0 ) {             innerView = getChildAt(0);         }     }       @Override     public boolean onTouchEvent(MotionEvent ev) {         if (innerView == null ) {             return super.onTouchEvent(ev);         } else {             commonTouchEvent(ev);         }         return super.onTouchEvent(ev);     }       /**      * 自定义touch事件处理      *      * @param ev      */     private void commonTouchEvent(MotionEvent ev) {         if (animationFinish) {             int action = ev.getAction();             switch (action) {                 case MotionEvent.ACTION_DOWN:                     y = ev.getY();                     break;                 case MotionEvent.ACTION_MOVE:                     float preY = y == 0 ? ev.getY() : y;                     float nowY = ev.getY();                     int detailY = ( int) (preY - nowY);                     y = nowY;                     //操作view进行拖动detailY的一半                     if (isNeedMove()) {                         //布局改变位置之前,记录一下正常状态的位置                         if (normal.isEmpty()) {                             normal.set(innerView.getLeft(), innerView.getTop(), innerView.getRight(), innerView.getBottom());                         }                         innerView.layout(innerView.getLeft(), innerView.getTop() - detailY / 2, innerView.getRight(), innerView.getBottom() - detailY / 2);                     }                     break;                 case MotionEvent.ACTION_UP:                     y = 0;                     //布局回滚到原来的位置                     if (isNeedAnimation()) {                         animation();                     }                     break;             }         }     }       private void animation() {         TranslateAnimation ta = new TranslateAnimation( 0, 0, 0, normal.top - innerView.getTop());         ta.setDuration(200);         ta.setAnimationListener(new Animation.AnimationListener() {             @Override             public void onAnimationStart(Animation animation) {                 animationFinish = false;             }               @Override             public void onAnimationEnd(Animation animation) {                 innerView.clearAnimation();                 innerView.layout(normal.left, normal.top, normal.right, normal.bottom);                 normal.setEmpty();                 animationFinish = true ;             }               @Override             public void onAnimationRepeat(Animation animation) {               }         });         innerView.startAnimation(ta);     }       /**      * 判断是否需要回滚      *      * @return      */     private boolean isNeedAnimation() {         return !normal.isEmpty();     }       /**      * 判断是否需要移动      *      * @return      */     private boolean isNeedMove() {         int offset = innerView.getMeasuredHeight() - getHeight();         int scrollY = getScrollY();         Log.e("zoubo", "getMeasuredHeight:" + innerView.getMeasuredHeight() + "----getHeight:" + getHeight());         Log.e("zoubo", "offset:" + offset + "----scrollY:" + scrollY);         if (scrollY == 0 || scrollY == offset) {             return true;         }         return false;     } }