zoukankan      html  css  js  c++  java
  • Scrollview回弹效果自定义控件

    滚动回弹效果分析:
    首先,创建一个类,继承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+超出部分。
     
    抬起的处理:布局回滚到正常位置
    移动动画回滚到正常位置(*:动画执行期间,不允许拖拉操作)   
    距离:-的滚动距离
    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;
        }
    }
    

      

     
  • 相关阅读:
    12.1
    我的火车头
    头文件优化时间
    一些姿势
    CodeForces
    CodeForces
    [SDOI 2015] 约数个数和
    BZOJ
    [国家集训队] middle
    鹅的问题
  • 原文地址:https://www.cnblogs.com/sixrain/p/6372897.html
Copyright © 2011-2022 走看看