第三章:View的事件体系
3.1 View的基础知识
主要有:View的位置参数,MotionEvent和TouchSlop对象,VelocityTracker,GestureDetector和Scroller对象
3.1.1 View
view是android中所有控件的基类,是一种界面层的控件的一种抽象.
ViewGroup(控件组),内部包含了很多个控件,即一组view
3.1.2 View的位置参数
View的位置主要由它的四个顶点来决定:top(左上角纵坐标),left(左上角横坐标),right(右下角横坐标),bottom(右下角纵坐标)
left = getLeft();
right = getRight();
top = getTop();
bottom = getBottom();
从android3.0开始,增加了:x,y,translationX和translationY,x和y是View的左上角的左边,而translationX和translationY是View左上角相对于父容器的偏移量.
x = left + translationX;
y = right + translationY;
3.1.3 MotionEvent和TouchSlop
1. MotionEvent
手指接触屏幕后产生一些列的事件,典型的事件如下
- ACTION_DOWN:手指刚接触屏幕
- ACTION_MOVE:手指在屏幕上移动
- ACTION_UP:手指从屏幕上松开的一瞬间
2. TouchSlop
是系统所能识别出被认为是滑动的最小距离.如果两次滑动之间的距离小过这个常量,系统就不认为你是在进行滑动操作
通过ViewConfiguration.get(getContext()).getScaledTouchSlop()获得这个常量.
3.1.4 VelocityTracker,GestureDetector和Scroller
1.VelocityTracker
速度追踪:用来追踪手指在滑动过程中的速度
首先在View的onTouchEvent方法中追踪当前点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
注意两点:第一,获取速度之前必须先计算速度,即在getXVelocity()和getYVelocity()方法之前要先调用computeCurrentVelocity方法,第二点,这里的速度是指一段时间内手指所划过的像素数
velocityTracker.computeCurrentVelocity(1000);//时间间隔为1000ms;
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
2. GestureDetector
手势检测
首先需要创建一个GestureDetector对象并实现OnGestureListener接口
GestureDetector mGestureDetector = new GestureDetector(this);
//解决长按屏幕后无法拖动的现象
mGestureDetector.setIsLongpressEnabled(false);
接着,接管目标View的onTouchEvent方法,在待监听View的onTouchEvent方法中实现
boolean consume = mGestureDetector.onTouchEvent(event);
retrun consume;
3. Scroller
弹性滑动对象,用于实现View的弹性滑动,使用scrollTo/scrollBy方法来进行滑动时,其过程是瞬间完成的.
3.2 View的滑动
3.2.1 使用scrollTo/scrollBy
scrollBy实际上也是调用了scrollTo方法,scrollBy它实现基于当前位置的相对滑动,scrollTo是基于所传递参数的绝对滑动
View内部的两个属性mScrollX(等于View左边缘和View内容左边缘在水平方向的距离)和mScrollY(等于View的上边缘和View内容上边缘在竖直方向的距离)的改变规则,通过getScrollX和getScrollY获得
从左往右滑动,mScrollX为负值,反之为正值;如果从上往下滑动,那么mScrollY为负值,反之为正值.
3.2.2 使用动画
使用View动画,但是会造成View的位置没有改变,动画完成后,View还是会停在原来的位置,所以要用属性动画
3.2.3 改变布局参数
布局参数:LayoutParams
MarginLayoutParams params = (MarginLayoutParams) mButton1.getLayoutParams();
params.width += 100;
params.leftHeight += 100;
mButton1.requestLayout();
//或者mButton1.setLayoutParams(params);
3.3 弹性滑动
3.3.1 使用scroller
Scroller Scroller = new Scroller(mContext);
//缓慢滚动到指定位置
private void smoothScrollTo(int destX, int destY){
int scrollX = getScrollX();
int deltaX = destX - scrollX;
//1000ms内滑向的destX,效果就是慢慢滑动
mScroller.startScroller(scrollX, 0, deltaX, 0, 1000);
invalidate();
} @Override
public void computeScroller(){
if (mScroller.computeScrollOfset()) {
mscrollTo(mScroller.getScrollX, mScroller.getCurrY());
postInvalidate();
}
}
Scroller本身并不能实现view的滑动,他需要配合View的computeScroll方法才能完成弹性滑动的效果它不断让view重绘,每一次重绘距滑动起始时间会有一个时间间隔,通过这个时间间隔就可以得出View当前的滑动位置,知道了滑动位置就可以通过scrollTo方法完成View的滑动.
3.3.2 通过动画
动画ObjectAnimator.ofFloat(targetView, "translationX", 0, 100).setDuration(1000).start();
3.3.3 使用延时策略
使用Handler发送消息sendMessage(),在handleMessage()方法中进行view的绘制
3.4 View的事件分发机制
3.4.1 点击事件的传递规则
有三个方法:
public boolean dispatchTouchEvent(MotionEvent ev):用来进行事件的分发.如果事件能够传递给当前View,那么次方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件.
public boolean onInterceptTouchEvent(MotionEvent event):用来判断是否拦截某个事件,如果当前view拦截了某个事件,那么在同一个事件序列当中,此方法不会再次调用,返回结果表示是否拦截当前事件
public boolean onTouchEvent(MotionEvent event):在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再次接收到事件.
一个点击事件产生后,它的传递过程遵循如下顺序:Activity->Window->View.
- 统一个事件序列是从手指接触屏幕的那一刻开始,到手指离开屏幕的那一刻结束(以down事件开始,中间含有数量不定的move事件,最终以up事件结束).
- 正常情况下,一个时间序列只能被一个View拦截并消耗.
- 某个View一旦决定拦截,那么这一个事件序列都只能由它栏处理,并且它的onInterceptTouchEvent不会再被调用.
- 某个View一旦开始处理事件,如果他不消耗ACTION_DOWN事件(onTouchEvent返回false),那么同一事件序列中的其它时间都不会再交给它被调用.
- 如果View不消耗ACTION_DOWN以外的其它时间,那么这个点击事件会小时,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续受到后续的时间,最终这些消失的点击事件会传递给Activity处理.
- ViewGroup默认不拦截任何时间
- View没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它的onTouchEvent方法就会调用
- VIew的onTouchEvent默认都会消耗事件(返回true),除非它是不可点击的(clickable和龙Clickable同时为false).
- View的enable属性不影响onTouchEvent的默认返回值.
- onClick会发生的前提是当前View是可点击的,并且它收到down和up的事件
- 事件传递过程是由外向内的,即事件总是先传递给父元素,然后再由父元素分发给子View,通过requestDisallowInterceptTouchEvent方法可以在子元素中敢于父元素的事件分发过程,但是ACTION_DOWN事件除外.
3.4.2 事件分发
1.Activity对点击事件的分发过程
点击事件用MotionEvent来表示,事件最先传递给当前Activity,由Activity的dispatchTouchEvent来进行事件派发,具体的工作是有Activity内部的Window来完成的.
Window会将事件传递给decor view ,decor view 一般就是当前界面的底层容器,通过Activity.getWindow.getDecorView()可以获得.
Window是一个抽象类,实现类是PhoneWindow,PhoneWindow将时间直接传递给DecorView
通过((ViewGroup)getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0)这种方式获取Activity所设置的View
而我们通过setContentView设置的View是它的一个子View.
2. 顶级View对点击事件的分发过程
点击事件到达顶级View(一般是一个ViewGroup)以后,会调用ViewGroup的dispatchTouchEvent方法
如果顶级ViewGroup拦截事件,即onInterceptTouchEvent返回true,则事件由ViewGroup处理,这时如果ViewGroup的mOnTouchListener被设置,则onTouchEvent会被调用,否则onTouchEvent会被调用.
onTouch会屏蔽掉onTouchEvent,
在onTouchEvent中,如果设置了mOnClickListener,则onClick会被调用.
如果顶级View不拦截,则事件会传递给它所在的点击事件链上的子View.
3. View对点击事件的处理过程
首先会判断有没有设置OnTouchListener,如果OnTouchListener中的onTouch方法返回true,那么onTouchEvent就不会被调用,OnTouchListener的优先级高于onTouchEvent
只要View的CLICKABLE和LONG_CLICKABLE有一个为true,那么他就会消耗这个事件,即onTouchEvent方法会返回true
3.5 View的滑动冲突
1. 外部滑动方向跟内部滑动方向不一致
2.外部滑动方向和内部滑动方向一致
3.上面两种情况的嵌套
3.5.2 滑动冲突的处理规则
根据滑动时水平滑动还是竖直滑动来判断到底由谁来拦截事件
根据具体的业务寻找具体规则
3.5.3 滑动冲突的解决方法
1.外部拦截法
点击事件都先经过父容器的拦截处理,如果父容器需要此事件被拦截,如果不需要此事件就不拦截
外部拦截发需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可
需要拦截,intercepted返回true,不拦截返回false
2.内部拦截法
指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理,需要配合requestDisallowInterptTouchEvent方法
需要重写子元素的dispatchTouchEvent方法.
第三章:View的事件体系的更多相关文章
- Android艺术开发探索第三章————View的事件体系(下)
Android艺术开发探索第三章----View的事件体系(下) 在这里就能学习到很多,主要还是对View的事件分发做一个体系的了解 一.View的事件分发 上篇大致的说了一下View的基础知识和滑动 ...
- Android艺术开发探索第三章——View的事件体系(上)
Android艺术开发探索第三章----View的事件体系(上) 我们继续来看这本书,因为有点长,所以又分了上下,你在本片中将学习到 View基础知识 什么是View View的位置参数 Motion ...
- 《Android开发艺术探索》读书笔记 (3) 第3章 View的事件体系
本节和<Android群英传>中的第五章Scroll分析有关系,建议先阅读该章的总结 第3章 View的事件体系 3.1 View基本知识 (1)view的层次结构:ViewGroup也是 ...
- 三、View的事件体系
1.View基础知识 1.1.什么是View View是Android中所有控件的基类.View是一种界面层的控件的一种抽象,代表了一个控件.除了View,还有ViewGroup,内部包含了许多个控件 ...
- Android开发艺术探索(三)——View的事件体系
一.View基础知识 主要介绍内容有:View的位置参数.MotionEvent和TouchSlope对象.VelocityTracker.GestureDetector和Scroller对象 1.什 ...
- Android View 的事件体系
android 系统虽然提供了很多基本的控件,如Button.TextView等,但是很多时候系统提供的view不能满足我们的需求,此时就需要我们根据自己的需求进行自定义控件.这些控件都是继承自Vie ...
- View的事件体系
View的滑动 实现手段 优点 缺点 备注 scrollTo/scrollBy 使用简单 只能滑动view的内容,并不会滑动view本身. 且内容超出view本身的布局范围部分的不会显示 不适合有交互 ...
- Android事件分发机制二:viewGroup与view对事件的处理
前言 很高兴遇见你~ 在上一篇文章 Android事件分发机制一:事件是如何到达activity的? 中,我们讨论了触摸信息从屏幕产生到发送给具体 的view处理的整体流程,这里先来简单回顾一下: 触 ...
- View事件体系
View事件体系 文章目录 View事件体系 一.Android View基础知识 1.1 View简介 1.2 View分类 1.3 View的结构 1.4 View的坐标 1.4.1 Androi ...
随机推荐
- vulstack红队评估(二)
一.环境搭建: 1.根据作者公开的靶机信息整理: 靶场统一登录密码:1qaz@WSX 2.网络环境配置: ①Win2008双网卡模拟内外网: 外网:192.168.1.80,桥接模式与物理机相 ...
- 第三模块 :微服务网关Zuul架构和实践
52.Zuul网关架构剖析~1.mp4 请求过来之后首先会通过前置过滤器,然后到路由过滤器,路由过滤器是真正访问后台远程服务的,经过路由器之后,最后会传递给后置过滤器 在三个过滤器处理的过程中任何一个 ...
- Java | 内部类(Inner Class)
前言 本文内容主要来自 Java 官方教程中的<嵌套类>章节. 本文提供的是 JDK 14 的示例代码. 定义 内部类(Inner Class),是 Java 中对类的一种定义方式,是嵌套 ...
- Python 简明教程 --- 20,Python 类中的属性与方法
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 与客户保持良好的关系可以使生产率加倍. -- Larry Bernstain 目录 类中的变量称为属 ...
- 入门大数据---Spark部署模式与作业提交
一.作业提交 1.1 spark-submit Spark 所有模式均使用 spark-submit 命令提交作业,其格式如下: ./bin/spark-submit \ --class <ma ...
- 如何解决TOP-K问题
前言:最近在开发一个功能:动态展示的订单数量排名前10的城市,这是一个典型的Top-k问题,其中k=10,也就是说找到一个集合中的前10名.实际生活中Top-K的问题非常广泛,比如:微博热搜的前100 ...
- 如何用Nearby Service开发针对附近人群的精准广告推送功能
当你想找一家餐厅吃饭,却不知道去哪家,这时候手机跳出一条通知,为你自动推送附近优质餐厅的信息,你会点击查看吗?当你还在店内纠结于是否买下一双球鞋时,手机应用给了你发放了老顾客5折优惠券,这样的广告 ...
- 113资讯网:安装程序进入Admin后台出现:SQLSTATE[HY000] [1045] Access denied for user'root'@'localhost' (using password: YES)
各项设置设置正确,就是出现这种原因! 1.config.inc.php解决办法: 修改phpMyAdmin的配置文件里的密码设置,进入phpMyAdmin的安装目录,找到config.inc.php配 ...
- Spring中AOP相关的API及源码解析
Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ...
- HTML5(五)Geolocation
HTML5 Geolocation 定位用户的位置 HTML5 Geolocation API 用于获得用户的地理位置. 鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的. 注意 ...