Android应用开发之自定义View触摸相关工具类全解(2)

static public VelocityTracker obtain() {}

public static VelocityTracker obtain(String strategy) {}

//回收后代表你不需要使用了,系统将此对象在此分配到其他请求者

public void recycle() {}

//清空回到初始状态,computeCurrentVelocity都被reset了

public void clear() {}

//将事件加入到VelocityTracker类实例中

public void addMovement(MotionEvent event) {}

//unitis表示速率的基本时间单位,1表示一毫秒时间单位内运动了多少个像素

public void computeCurrentVelocity(int units) {}

//同上,floatVelocity表示速率的最大值,超过最大值的都返回最大值

public void computeCurrentVelocity(int units, float maxVelocity) {}

//获取xy方向速率

public float getXVelocity() {}

public float getYVelocity() {}

//获取xy速率,id为event的pointid

public float getXVelocity(int id) {}

public float getYVelocity(int id) {}

}

有了上面这些手势速率的检测工具类,下面我们来看下他的一些通用模板:

VelocityTracker mVelocityTracker = null;

@Override

public boolean onTouchEvent(MotionEvent event){

int action = event.getAction();

switch(action){

case MotionEvent.ACTION_DOWN:

if(mVelocityTracker == null){

mVelocityTracker = VelocityTracker.obtain();

}else{

mVelocityTracker.clear();

}

mVelocityTracker.addMovement(event);

break;

case MotionEvent.ACTION_MOVE:

mVelocityTracker.addMovement(event);

mVelocityTracker.computeCurrentVelocity(1000);

Log.i("X = "+mVelocityTracker.getXVelocity());

Log.i("Y = "+mVelocityTracker.getYVelocity());

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

mVelocityTracker.recycle();

break;

}

return true;

}

关于速率检测类的知识就介绍到这里,没啥新鲜的。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

GestureDetector手势工具类

========================

除了我们通过onTouchEvent()自己处理一堆复杂的手势以外,其实Android给我们提供了现成的便捷方式,那就是GestureDetector手势监听类,如下:

public class GestureDetector {

public interface OnGestureListener {

//ACTION_DOWN时触发

boolean onDown(MotionEvent e);

//ACTION_DOWN了过一会还没有滑动时触发,onDown->onShowPress->onLongPress

void onShowPress(MotionEvent e);

//ACTION_DOWN后没有滑动(onScroll)且没有长按(onLongPress)接着ACTION_UP时触发

boolean onSingleTapUp(MotionEvent e);

//滑动时实时触发

boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);

//ACTION_DOWN长按时触发

void onLongPress(MotionEvent e);

//触摸滑动一定距离后松手ACTION_UP时触发,后参数为速率

boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);

}

public interface OnDoubleTapListener {

//ACTION_DOWN后没有滑动(onScroll)且没有长按(onLongPress)接着ACTION_UP时触发

boolean onSingleTapConfirmed(MotionEvent e);

//双击的第二下ACTION_DOWN时触发

boolean onDoubleTap(MotionEvent e);

//双击的第二下ACTION_DOWN和ACTION_UP都会触发,e.getAction()区别

boolean onDoubleTapEvent(MotionEvent e);

}

public interface OnContextClickListener {

//context点击触发,与View#onGenericMotionEvent(MotionEvent)相关,不常用

boolean onContextClick(MotionEvent e);

}

public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,

OnContextClickListener {

//OnGestureListener、OnDoubleTapListener、OnContextClickListener所有接口的默认实现

}

//各种推荐的不推荐的构造方法

@Deprecated

public GestureDetector(OnGestureListener listener, Handler handler) {}

@Deprecated

public GestureDetector(OnGestureListener listener) {}

public GestureDetector(Context context, OnGestureListener listener) {}

public GestureDetector(Context context, OnGestureListener listener, Handler handler) {}

public GestureDetector(Context context, OnGestureListener listener, Handler handler,

boolean unused) {}

//其他两类回调接口的设置,OnGestureListener必须在构造中就处理掉

public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {}

public void setContextClickListener(OnContextClickListener onContextClickListener) {}

//一些处理判断方法

public void setIsLongpressEnabled(boolean isLongpressEnabled) {}

public boolean isLongpressEnabled() {}

public boolean onTouchEvent(MotionEvent ev) {}

public boolean onGenericMotionEvent(MotionEvent ev) {}

}

有了上面这些GestureDetector手势工具类的基本API介绍之后我们就可以各种使用了,没啥特殊的介绍。

特别注意: 其实手势相关的东西还有Gesture类等GestureOverlayView手势创建识别类的,这里不作介绍,作为拓展。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

View及ViewGroup触摸事件总结

========================

关于View触摸屏事件的传递机制源码分析其实可以参考我前面写的博客,这篇文章既然是总结,那就是只给出结论,相关分析请看前面的博文。

触摸事件传递源Activity:

Activity的dispatchTouchEvent()方法将事件传递给它的根布局ViewGroup(即调用根布局ViewGroup的dispatchTouchEvent()方法,该方法会对事件进行如下情况处理:

  • 如果根布局ViewGroup及其内部子布局控件均没处理(此时根布局ViewGroup的dispatchTouchEvent()方法返回false)则调用Activity自己的onTouchEvent()方法;如果Activity自己的onTouchEvent()方法仍然没有处理(返回false)则该事件处理宣告结束。

  • 如果根布局ViewGroup的dispatchTouchEvent()方法返回true则表明根布局中处理了这一次事件,此时就不会再调用Activity的onTouchEvent()方法了(因为Activity没有父控件且不能设置触摸监听OnTouchListener,所以没有onInterceptTouchEvent()方法)。

触摸事件传递View级别处理:

这里所谓的View级别泛指其内部不包含子控件(已经为最小控件单位)的View,当该View的父级ViewGroup触发该View的dispatchTouchEvent()方法时,由于该View没有子控件可以被继续派发,所以事件只能自己调度自己相关方法。测试的调度如下:

  • 如果该View注册了OnTouchListener,则优先调用OnTouchListener的onTouch()方法,如果onTouch()方法返回false则继续调运该View的onTouchEvent()方法,如果onTouch()方法返回true则该View的dispatchTouchEvent()方法直接返回true。

  • 如果该View没有注册OnTouchListener则直接调用该View的onTouchEvent()方法,该方法返回true、false决定了该View的dispatchTouchEvent()方法返回值。

触摸事件传递ViewGroup级别处理:

ViewGroup的dispatchTouchEvent()方法被其父布局 (父ViewGroup或者Activity)调用,当前ViewGroup的dispatchTouchEvent()方法主要任务就是为子控件派发事件(调运子控件的dispatchTouchEvent()),同时向父级布局返回事件处理情况。

不过在当前ViewGroup的dispatchTouchEvent()方法向子控件派发事件之前我们在当前ViewGroup里是可以通过自己的onInterceptTouchEvent()方法来决定触摸事件是否拦截(当前ViewGroup的onInterceptTouchEvent()返回true则不再传递给自己的子控件,而是当前ViewGroup自己处理,接着将处理结果告诉父控件;返回false则不拦截(继续传递给子控件,如果子控件的dispatchTouchEvent()方法都返回false则ViewGroup就尝试自己处理事件,然后告诉父布局自己处理的结果)。

一次完整的事件流程处理:

综合从Activity到根ViewGroup到中间ViewGroup,再到View的事件处理流程,我们要注意其传递过程中的下面几点:

  • 一次完整的事件触发可以分为ACTION_DOWN->[ACTION_MOVE]->ACTION_UP。当我们手指按下派发ACTION_DOWN事件时,如果我们当前层级的View或者ViewGroup的onTouch()或onTouchEvent()方法返回false,则当前层级的View或者ViewGroup的onTouch()或onTouchEvent()方法就再也接收不到其他事件了,直到下次新的触摸事件(ACTION_DOWN)开始。

  • 在一次完整的事件传递(ACTION_DOWN->[ACTION_MOVE]->ACTION_UP)过程中只要当前ViewGroup的onInterceptTouchEvent()方法有一次返回true则当前ViewGroup将会拦截这次事件传递的全部后续触发事件,同时这些后续触发事件都不会再触发当前ViewGroup的onInterceptTouchEvent()方法(直到下次ACTION_DOWN来临),同时向之前处理事件的子布局传递一个ACTION_CANCEL事件。如果当前ViewGroup的onInterceptTouchEvent()方法返回false,则本次传递的每个事件来临时都会触发当前ViewGroup的onInterceptTouchEvent()方法。

  • 只有ViewGroup才有onInterceptTouchEvent()方法,因为最小单位的View不具备再往下派发事件的能力,它只会直接调用自己的onTouch()和onTouchEvent()方法。

  • 当父ViewGroup截获了当前传递事件,常理来说其内部的子布局View或者ViewGroup就不能够再收到派发事件了;但是我们有一种方法可以阻止父ViewGroup截获传递的事件(getParent().requestDisallowInterceptTouchEvent(true);),一旦子布局View或者ViewGroup收到触摸事件后调用这个方法则父ViewGroup就不会再调用她自己的onInterceptTouchEvent()方法了,直到事件处理完毕再getParent().requestDisallowInterceptTouchEvent(false);即可。

到此View的触摸事件传递也就总结完成了,使用中牢记这些准则即可,当然也推荐查看源码。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

总结

======

可以看见,关于自定义控件的基础触摸相关的东西其实差不多也就这么多了,有了上面这些玩意你也基本上就能够玩转Android自定义控件触摸相关的蛋疼处理了,不用再苦苦思索了。

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2020-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节

还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

一线互联网面试专题

379页的Android进阶知识大全

379页的Android进阶知识大全

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

片转存中…(img-LZbujZmR-1714407791631)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值