Android 自定义view《九》 View的滑动实现 360悬浮球实现 (从入门到巅峰)

一滑动效果的产生

滑动一个View,本质区别就是移动一个View。改变当前View所在的坐标,原理和动画相似不断改变坐标位置实现。实现View的滑动就必须监听滑动的事件,并且根据事件传入的坐标,动态且不断改变View的坐标,从而实现View跟随用户触摸的滑动而滑动。

 

(1)、Android的坐标系

系统提供了getLocationOnScreen(int location[])这样的方法来获取Android坐标系中点的位置,即该视图左上角在Android坐标系中的坐标。

在触控事件中使用getRawX()、getRawY()方法所获得的坐标同样是Android坐标系中的坐标。

 

(2)、视图坐标系

 

Android坐标系类似,视图坐标系同样是以原点向右为X轴正方向,以原点向下为Y轴正方向,只不过在视图坐标系中,原点不再是Android坐标系中的屏幕最左上角,而是以父视图左上角为坐标原点,如下图:

在触控事件中,通过getX()、getY()所获得的坐标系就是视图坐标系中的坐标。

 

(3)、触控事件——MotionEvent

触控事件MotionEvent在用户交互中,占着举足轻重的地位。首先看看MotionEvent封装的一些常用事件常量,定义了触控事件的不同类型。

 

//单点触摸按下动作
public static final int ACTION_DOWN             = 0;

//单点触摸离开动作
public static final int ACTION_UP               = 1;

//触摸点移动动作
public static final int ACTION_MOVE             = 2;

//触摸动作取消
public static final int ACTION_CANCEL           = 3;

//触摸动作超出边界
public static final int ACTION_OUTSIDE          = 4;

//多点触摸按下动作
public static final int ACTION_POINTER_DOWN     = 5;

//多点离开动作
public static final int ACTION_POINTER_UP       = 6;

 

通常情况会在onTouchEvent(MotionEvent event)方法中通过event.getAction()方法来获取触控事件的类型,并使用switch-case方法来进行筛选,这个代码的模式基本固定:

@Override
public boolean onTouchEvent(MotionEvent event) {
    //获取当前输入点的X、Y坐标(视图坐标)
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //处理按下事件
            break;
        case MotionEvent.ACTION_MOVE:
            //处理移动事件
            break;
        case MotionEvent.ACTION_UP:
            //处理离开事件
            break;
    }
    return true;
}

 

 

坐标总结:

  • View提供的获取坐标方法
    • getTop():获取到的是View自身的顶边到其父布局顶边的距离。
    • getLeft():获取到的是View自身的左边到其父布局最左边的距离。
    • getRight():获取到的是View自身的右边到其父布局左边的距离。
    • getBottom():获取到的是View自身的底边到其父布局顶边的距离。
  • MotionEvent提供的方法
    • getX():获取点击事件距离空间左边的距离,即视图坐标。
    • getY():获取点击事件距离控件顶边的距离,即视图坐标。
    • getRawX():获取点击事件距离整个屏幕左边的距离,即绝对坐标。
    • getRawY():获取点击事件距离整个屏幕顶边的距离,即绝对坐标。

 

实现滑动的七种方式

(1)layout方法

// 视图坐标方式
@Override
public boolean onTouchEvent(MotionEvent event) {
    int x = (int) event.getRawX();
    int y = (int) event.getRawY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 记录触摸点坐标
            lastX = x;
            lastY = y;
            break;
        case MotionEvent.ACTION_MOVE:
            // 计算偏移量
            int offsetX = x - lastX;
            int offsetY = y - lastY;
            // 在当前left、top、right、bottom的基础上加上偏移量
            layout(getLeft() + offsetX,
                    getTop() + offsetY,
                    getRight() + offsetX,
                    getBottom() + offsetY);
            //重新设置初始化坐标
            lastX = x;
            lastY = y;
            break;

    }
    return true;
}

来源: https://www.jianshu.com/p/861743aa9186

(2)、offsetLeftAndRight()与offsetTopAndBottom()

这个方法相当于系统提供的一个对左右、上下移动的API的封装。当计算出偏移量后,只需要使用如下代码就可以完成View的重新布局,效果与使用Layout方法一样,代码如下所示:

//同时对left和right进行偏移
offsetLeftAndRight(offsetX);
//同时对top和bottom进行偏移
offsetTopAndBottom(offsetY);

这里的offsetX、offsetY与在layout方法中计算offset方法一样。

(3)、LayoutParams

LayoutParams保存了一个View的布局参数。因此可以在程序中,通过改变LayoutParams来动态地修改一个布局的位置参数,从而达到改变View位置的效果。我们可以很方便在程序中使用getLayoutParams()来获取一个View的LayoutParams。当然,计算偏移量的方法与在Layout方法中计算offset也是一样。当获取到偏移量之后,就可以通过setLayoutParams来改变其LayoutParams,代码如下:

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

这里getLayoutParams()获取LayoutParams时,需要根据View所在View父布局的类型来设置不同的类型,比如这里将View放在LinearLayout中,那么就可以使用LinearLayout.LayoutParams。如果在RelativeLayout中,就要使用RelativeLayout.LayoutParams。这一切的前提是你必须要有一个父布局,不然系统无法获取LayoutParams。

在通过改变LayoutParams来改变一个View的位置时,通常改变的是这个View的Margin属性,所以除了使用布局的LayoutParams之外,还可以使用ViewGroup.MarginLayoutParams来实现这一一个功能,代码:

ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

我们可以发现,使用ViewGroup.MarginLayoutParams更加的方便,不需要考虑父布局的类型,当然它们的本质都是一样。

(4)、scrollTo与scrollBy

在一个View中,系统提供了scrollTo、scrollBy两种方式来改变一个View的位置。这两个方法的区别非常好理解,与英文中To与By的区别类似,scrollTo(x,y)表示移动到一个具体的坐标点(x,y),而scrollBy(dx,dy)表示移动的增量为dx,dy。

(5)、Scroller

 

(6)、属性动画和动画

 

 

 

 

 

 

 

 

参考博客:

自定义View之滑动事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值