Android群英传之Android 滑动分析

1、Android中获取坐标的方法

1)View提供的方法

getTop:view自身的顶边到父布局顶边的距离
getLeft:view的左边到父布局的左边
getRight:view的右边到父布局的左边
getBottom:view底边到父布局的顶边

2)MotionEvent提供的方法

getX:点击事件到控件左边
getY:点击事件到控件顶边
getRawX:获取点击事件的绝对X坐标
getRawY:获取点击事件的绝对Y坐标

2、实现滑动的七种方法

1)layout方法

修改上下左右四个坐标


@Override
public boolean onTouchEvent(MotionEvent event) {
    int rawX = (int) event.getRawX();
    int rawY = (int) event.getRawY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //记录触摸点坐标
            lastX = rawX;
            lastY = rawY;
            break;
        case MotionEvent.ACTION_MOVE:
            //计算偏移量
            int offsetX = rawX - lastX;
            int offsetY = rawY - lastY;
            //在当前left、top、right、bottom家上偏移量
            layout(getLeft()+offsetX, getTop()+offsetY, getRight()+offsetX,getBottom()+offsetY);
            //重设初始坐标
            lastX = rawX;
            lastY = rawY;
            break;
    }
    return true;
}

2)offsetLestAndRight与offsetTopAndBottom

同理layout方法,改变上下左右四个坐标

@Override
public boolean onTouchEvent(MotionEvent event) {
    int rawX = (int) event.getRawX();
    int rawY = (int) event.getRawY();


    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //记录触摸点坐标
            lastX = rawX;
            lastY = rawY;
            break;
        case MotionEvent.ACTION_MOVE:
            //计算偏移量
            int offsetX = rawX - lastX;
            int offsetY = rawY - lastY;
            //offsetLeftAndRight和offsetTopAndBottom方法
            offsetLeftAndRight(offsetX);
            offsetTopAndBottom(offsetY);
            //重设初始坐标
            lastX = rawX;
            lastY = rawY;
            break;
    }
    return true;
}

3)LayoutParams

改变左外边距和右外边距来实现滑动

@Override
public boolean onTouchEvent(MotionEvent event) {
    int rawX = (int) event.getRawX();
    int rawY = (int) event.getRawY();


    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //记录触摸点坐标
            lastX = rawX;
            lastY = rawY;
            break;
        case MotionEvent.ACTION_MOVE:
            //计算偏移量
            int offsetX = rawX - lastX;
            int offsetY = rawY - lastY;

            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
            layoutParams.leftMargin = getLeft() + offsetX;
            layoutParams.topMargin = getTop() + offsetY;
            setLayoutParams(layoutParams);
            /**
             * 不用考虑父布局类型的写法
             * ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
             * layoutParams.leftMargin = getLeft() + offestX;
             * layoutParams.topMargin = getTop() + offsetY;
             * setLayoutParams(layoutParams);
             */
            //重设初始坐标
            lastX = rawX;
            lastY = rawY;
            break;
    }
    return true;
}

4)scrollTo和scrollBy

指的是view的内容的移动,也就是说对于TextView就是移动里面的文字,想要移动TextView本身就要让其父布局调用此方法。scrollTo一般传入绝对坐标,scrollBy一般传入偏移量。另外,记住,这两个方法都是进行反向移动,想要达到自己目的,就要对参数进行变换。

@Override
public boolean onTouchEvent(MotionEvent event) {
    int rawX = (int) event.getRawX();
    int rawY = (int) event.getRawY();


    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //记录触摸点坐标
            lastX = rawX;
            lastY = rawY;
            break;
        case MotionEvent.ACTION_MOVE:
            //计算偏移量
            int offsetX = rawX - lastX;
            int offsetY = rawY - lastY;
            //scrollTo适用于绝对坐标,scrollBy适用于偏移量,并且都是移动View的内容
            //偏移量取反
            ((View) getParent()).scrollBy(-offsetX, -offsetY);
            //重设初始坐标
            lastX = rawX;
            lastY = rawY;
            break;
    }
    return true;
}

5)Scroller

平滑移动,主要重写了View的computeScroll方法
下面的代码,不仅实现滑动,也实现了松手后滑回原位置

final Scroller mScroller = new Scroller(this);
View view5 = new View(this) {
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(200, 100);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.GREEN);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        //判断Scroller是否执行完毕
        if (mScroller.computeScrollOffset()) {
            ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //通过不断重绘来不断调用computeScroll
            invalidate();
        }
    }

    int lastX, lastY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //记录触摸点坐标
                lastX = rawX;
                lastY = rawY;
                break;
            case MotionEvent.ACTION_MOVE:
                //计算偏移量
                int offsetX = rawX - lastX;
                int offsetY = rawY - lastY;
                ((View) getParent()).scrollBy(-offsetX, -offsetY);
                //重设初始坐标
                lastX = rawX;
                lastY = rawY;
                break;

            //加入效果,手指离开时,执行滑动过程
            case MotionEvent.ACTION_UP:
                View viewGroup = (View) getParent();
                mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY());
                invalidate();
                break;
        }
        return true;
    }
};

6)属性动画实现

推荐阅读:Android动画

7)ViewDragHelper

非常强大,侧滑组件就是用此来实现的。

  • 初始化ViewDragHelper
    第一个参数为父布局,第二个参数为回调,是核心所在
mViewDragHelper = ViewDragHelper.create(this, callBack);
  • 接下来就实现回调
private ViewDragHelper.Callback callBack = new ViewDragHelper.Callback() {
    //何时开始检测触摸事件
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
        //如果当前触摸的child是mMainView时开始检测
        return mMainView == child;
    }

    //处理垂直滑动
    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        return 0;
    }

    //处理水平滑动
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
        return left;
    }

    //拖动结束后调用
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
        super.onViewReleased(releasedChild, xvel, yvel);
        //手抬起后缓慢移动到指定位置
        if (mMainView.getLeft() < 500) {
            //关闭菜单
            //相当于Scroller的startScroll方法
            mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
            ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
        } else {
            //打开菜单
            mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
            ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
        }
    }
};
  • 拦截事件。因为滑动效果,总是会事件分发机制相关,所以ViewDragHelper会处理相应的事件。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return mViewDragHelper.shouldInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    mViewDragHelper.processTouchEvent(event);
    return true;
}
  • 最后处理computeScroll,因为ViewDragHelper内部也是用scroller实现平滑移动
@Override
public void computeScroll() {
    if (mViewDragHelper.continueSettling(true)) {
        ViewCompat.postInvalidateOnAnimation(this);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值