Android Touch事件前言

前言:其实我现在倒是觉得看起来很简单的东西越显得重要,之前总是一昧的追求底层,最后才发现忽略了很多东西,最后提醒大家,不要忽略简单的东西,对待技术不要忽略任何一个细节,任何时候都得讲究循环渐进,在研究一项比较复杂的技术之前一定要让自己首先具备这个条件。

我们知道关于Android事件分发机制在网上可以找到一堆,其实都很多都是理论结合demo演示下就结束了,当然了也有分析的特别好的,结合源码分析的很透彻。读了之后受益匪浅,但是呢,都不是我想要的,或者说我觉得这里应该需要再分析的透彻点,这里要牵扯到其他东西,需要单说等等。所以呢就有了这篇博客,主要是自己给自己记录下,以后也方便查看,在写之前也参考了一些书籍以及别人的博客,其实Android关于Touch在Android开发之中算是一个难点,也算是一个简单点。在讲之前,我需要先讲讲View的基础知识,那么就开始吧。

View基础知识
1.1 什么是View?
我们都知道View是Android中所有控件的基类,不管是TextView,Button还是LinearLayout也好等都继承自View,除了View还有ViewGroup,从名子上来看View组,言外之意就是用来放控件的,内部可以包含诸多个控件,即一组View,在Android设计之中ViewGroup也继承自View,从道理上来说ViewGroup说到底还是个View,所以在Android中所有的控件都继承自View或者ViewGroup,LinearLayout是一个ViewGroup也是个View,他内部可以放多个子View,同样这个ViewGroup也是View,依次类推,学过Web前端的应该知道其实这和Web前端里面DOM树的原理是类似的。

1.2 View的位置参数
1.首先你得明白一个东西,Android里面是没有圆图的,其实在Android之中任何View他的位置都是由他的四个顶点来决定的,即left、top、right、bottom,left对应左上角X轴坐标,top对应左上角Y轴坐标,right对应右下角X轴坐标,bottom对应右下角Y轴坐标。你得注意这些坐标都是相对坐标,也就是说这些坐标是相对于View的父容器来说的

View的位置参数

2.关于MotionEvent想必大家都比较熟悉,在手指触摸到屏幕之后产生的一系列动作,典型的几种简单有以下几种:
ACTION_DOWN——–手指刚接触到屏幕(按下事件)
ACTION_MOVE———手指在屏幕上移动(滑动事件)
ACTION_UP————-手指抬起的一瞬间(抬起事件)
正常情况下,一次点击屏幕会发生ACTION_DOWN——>ACTION_UP
如果有滑动操作又会:ACTION_DOWN——>ACTION_MOVE…>ACTION_UP等。
这几种事件类型正是我们工作之中经常遇到的,相信随你来说最简单不过了,同时通过MotionEvent对象我们可以拿到Touch事件的顶点坐标,我们都知道手机屏幕正是一个平面直角坐标系,通过getX()/getY()和getRawX()/getRawY()拿到X轴和Y轴的坐标,两个方法的区别很简单,getX()拿到的坐标是手指相对于View本身的坐标,而getRawX()拿到的是手指相对于手机屏幕的坐标。

3.TouchSlop
说到TouchSlop我又不得不说Scoller(弹性滑动),先来了解下TouchSlop吧,首先提一个问题,不知道大家有没有这样一个疑问,关于滑动事件我们几乎每天都与之打交道,Android系统内置了很多控件供我们使用,比如ViewPager,大家都知道我们在滑动翻页的时候如果滑动的距离比较小则滑不过去,反之滑的比较多则开始翻页,关于这个滑动的距离是怎么样一种定义呢?如果让你实现各ViewPager的功能你又会怎么实现?其实在Android开发中关于系统所能识别或者说能够认为这是个滑动操作的一种定义其实就是TouchSlop,首先我得跟你说它是一个常量,对就是一个固定的值,但是这个值是可变的,在不同的手机上面获取的可能不一样,道理很简单,肯定做了适配了。
TouchSlop是Android系统所能识别出的被认为是滑动的最小距离,即,当我们手指在屏幕上面按下这时候可以通过action_down获取到按下的坐标,然后开始滑动,通过action_move获取滑动时候的坐标,然后算出偏移量,即detailX,如果呢这个detailX大于TouchSlop则系统认为这是个滑动事件,可以通过ViewConfiguration.get(context).getScaledTouchSlop()来获取这个TouchSlop,这个常量对我们来说又有什么意义呢?其实在我们处理滑动事件的时候不妨利用这个TouchSlop来过滤下,即两次的滑动距离如果大于TouchSlop则产生了滑动事件,这就像一个临界值一样,突破了他就可以认为用户滑动了,反之则没有滑动。

4.再说Scroller,刚刚在上面也有通过,称之为弹性滑动,Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。而如果能够把Scroller的用法熟练掌握的话,我们自己也可以轻松实现出类似于ViewPager这样的功能,简而言之,Scroller扮演的角色还是很重要的,在上面我们提过ViewPager,如果看过ViewPager源码就应该知道内部是使用Scroller来实现的,说到这样代表我们也是可以自定义自己的ViewPager的,在把这个说清楚之前我又得先跟你说两个方法scrollTo(x,y)和scrollBy(x,y),这两个方法是View之中的,用来处理View的滚动。先看看源码,

/**
 * @param x the amount of pixels to scroll by horizontally
 * @param y the amount of pixels to scroll by vertically
 */
public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
}

/**
 * @param x the x position to scroll to
 * @param y the y position to scroll to
 */
public void scrollTo(int x, int y) {
    if (mScrollX != x || mScrollY != y) {
        int oldX = mScrollX;
        int oldY = mScrollY;
        mScrollX = x;
        mScrollY = y;
        onScrollChanged(mScrollX, mScrollY, oldX, oldY);
        if (!awakenScrollBars()) {
            invalidate();
        }
    }
}

从源码中可以看到其实scrollBy方法底层也是在调用scrollTo方法,首先跟你提下这两个方法都是用来处理View的滚动的,接收两个参数代表把当前View滚动到另一个位置,受参数影响。先看scrollTo方法,接收两个参数,无论scrollTo,也好scrollBy也罢,这里传入的并不是坐标,而是偏移量,根据官方文档介绍,当我们调用scrollTo(int x, int y)方法时,该方法内部将会去调用onScrollChanged(int, int, int, int),这也将直接导致view重绘,也就实现了所谓的view滑动效果。而scrollBy(int x ,int y)直接去调用了scrollTo方法,每次基于传入的参数加上偏移量,不难看出这个方法是在相对滑动也就是说相对于它上次的位置滑动,scrollTo(int x, int y)是基于所给参数的绝对滑动,而scrollBy(int x, int y)是基于所给参数的相对滑动,简单一句,scrollTo()是一步到位,而scrollBy()是逐步累加,这点很容易明白,从源码就能看出来了。但是scrollTo或者scrollBy到底是改变了啥啊?mScrollX和mScrollY又是个什么鬼?

/**
* The offset, in pixels, by which the content of this view is scrolled
* horizontally.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = “scrolling”)
protected int mScrollX;
/**
* The offset, in pixels, by which the content of this view is scrolled
* vertically.
* {@hide}
*/
@ViewDebug.ExportedProperty(category = “scrolling”)
protected int mScrollY;

其实这两个参数正是X轴和Y轴的偏移量,(右滑偏移量为负,左滑偏移量为正)

这里写图片描述

由此可知我们调用scrollTo(int x, int y)和scrollBy(int x, int y)时传递的参数并非是坐标而是偏移量。有一点需要提下:调用这两个方法发生滚动的是内容,比如我们view是TextView,那么我们调用scrollTo或者scrollBy方法时,移动的其实就是TextView的内容,但如果我们的view是LinearLayout(ViewGroup),那么移动其实就是该布局内的子view了。到此也算明朗了。android的view内容也提供了获取这两个偏移量大小的方法,如下:

  /**
 * @return The left edge of the displayed part of your view, in pixels.
 */
public final int getScrollX() {
    return mScrollX;
}

/**
 * @return The top edge of the displayed part of your view, in pixels.
 */
public final int getScrollY() {
    return mScrollY;
}

总结:
1.scrollTo()和scrollBy()都能使View滚动,scrollBy()调用的其实也就是scrollTo()方法
2.scrollTo()的移动是一步到位,而scrollBy()逐步累加的
3.scrollTo()和scrollBy()传递的参数是偏移量而非坐标
4.scrollTo()和scrollBy()移动的都只是View的内容,View的背景本身是不
移动的。
5.偏移量scrollX = 原点-右滑的X轴坐标,即右滑偏移量为负,左滑偏移量为正。

接下来,我们来说说Scroller而了,弹性滑动,能够辅助我们的View完成一个平滑的过渡,具体是什么意思呢?刚刚在上面我们有提到关于View的滚动scrollTo()方法,比如:scrollTo(-100,0)表示将当前View向右沿着X轴滑动100个像素,这个过程是一步到位的,我们看不到这个滑动过程的,但是如果想要实现这样的效果呢,在你手指up的时候看到View一点一点的平滑过去,这时候就要用到Scroller,其实他只是一个辅助类,在Android中扮演着View的滑动辅助,其底层还是在不断调用scrollTo方法进行View的重绘,其实原理也很简单原来一步到位的东西,现在被分割成一点一点,次数多了自然而然就形成了弹性滑动的效果。Scroller在使用方面也很固定,必须结合View的computeScroller方法完成弹性滑动。
1.实现你需要实例化一个Scroller:
Scroller scroller = new Scroller(context);
2.调用Scroller.startScroll(int startX, int startY, int dx, int dy, int duration)
参数解析:
startX:滑动的起始x轴坐标值(可以通过当前View.getScrollX()获取)
startY:滑动的起始y轴坐标值(可以通过当前View.getScrollY()获取)
dx:滑动的结束x轴坐标值
dy:滑动的结束y轴坐标值
duration:滑动的执行时间,这个可以具体根据需求设置,其中duration还与Scroller.computeScrollOffset()方法有关,这个方法内部会根据duration去判断滑动是否已经结束。如果结束,Scroller.computeScrollOffset()返回false,未结束返回true。
关于dx和dy如果不理解可以这样理解,当你手指将要up的时候,这时候x轴或者y轴滑动的距离或者位置
注意:右滑startX为负,左滑startX为正
3.执行View的回调computeScrollOffset

@Override  
public void computeScroll() {  
    if(scroller.computeScrollOffset()){  
        scrollTo(scroller.getCurrX(),scroller.getCurrY());  
        //重绘  
        postInvalidate();  
    }  
}  

这个方法会判断当前View的滑动有没有结束,结束返回false,未结束返回true,其实到这里也可以看出弹性滑动实质是在不断的小幅度调用scrollTo方法进行滚动,每调用一次都会使当前View进行重绘,也就看到了View的弹性滑动效果。这个弹性滑动所持续的时候也就是前面你所设置的duration。

5.VelocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括X轴和Y轴的追踪,其使用特别简单。首先你需要在你View的OnTouchEvent中追踪当前单击事件的速度

VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);

接着我们要想知道当前滑动的速度时,这个时候可以采取下列方式来获取:

velocityTracker.computeCurrentVelocity(1000);
float xVelocity = velocityTracker.getXVelocity();
float yVelocity = velocityTracker.getYVelocity();

有两点需要注意下:第一在获取速度之前必须先计算速度,也就是说在调用getXVelocity()和getYVelocity()之前必须先调用computeCurrentVelocity方法。第二点这里的速度时指单位时间内手指移动的像素数,这里将时间间隔设置为1000毫秒,也就是说在1秒内手指在水平方向从左向右滑动100个像素,那么水平速度就是100,当然速度也可以为负值,当手指从右往左滑动的时候。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值