Android事件拦截机制

Android中事件的传递和拦截和View树结构是相关联的,在View树中,分为叶子节点和普通节点,普通节点有子节点只能是ViewGroup,叶子节点可以是View或者ViewGroup。Android和事件分发拦截相关的方法有
dispatchTouchEvent(MotionEvent ev)
事件分发相关的方法,沿着View树将一个用户的触摸事件向下分发。
onInterceptTouchEvent(MotionEvent ev)
在dispatchTouchEvent中被调用,用来判断某一层级是否拦截一个事件,返回true即拦截,事件不会再向下分发,注意View树中叶子节点(View和ViewGroup)直接拦截事件。
onTouchEvent(MotionEvent ev)
一个某一个层级拦截了事件,那么所有事件序列都会交由它处理,后面onInterceptTouchEvent不会再被调用,转而onTouchEvent被调用。OnTouchEvent返回true则消耗掉这个事件序列,如果没有消耗ACTION_DOWN事件则事件序列将沿着View树向上传递,去找能处理这个事件的父View。如果消耗了ACTION_DOWN而没有消耗其它事件,那么这个事件序列将消失。
整体过程描述:事件产生传递到某一个ViewGroup时,首先其onInterceptTouchEvent会被调用,如果当前ViewGroup选择拦截这个事件则返回true,于是它的onTouchEvent会被调用。否则将继续调用子View的dispatchTouchEvent进行方法的拦截判断和相应的处理。
当一个View处理事件时,首先会调用它的OnTouchListener,如果OnTouchListener返回false则会继续调用onTouchEvent,在onTouchEvent中才会检查onClickListener,由此可见三种处理事件方法的优先级是:OnTouchListener > onTouchEvent > onClickListener。
ScrollTo,ScrollBy,Scroller
在实现滑动效果的时候,最常用的三个方法就是ScrollTo,ScrollBy和Scroller
首先介绍ScrollTo和ScrollBy,两个方法一个是滑动到某个位置,一个是滑动多少位置。关键在于,ScrollTo和ScrollBy对于普通的View组件比如TextView、ImageView的效果是移动View的内容,也就是相应的字体、照片,仅对于ViewGroup才是移动所有的子View。也就是说,ScrollTo和ScrollBy通常用在自定义的ViewGroup实现滑动效果时。
其次要理解ViewGroup滑动的坐标系,如下图左边是滑动前的布局,一个ViewGroup下面有两个子View,在ViewGroup中调用ScrollTo(0,300)就是将ViewGroup向下滑动,可以将ViewGroup看做一个透明窗口,向下滑动后第一个子View消失不见,第二个子View相对效果即是向上滑动。所以这里要注意ScrollTo和ScrollBy的正负值,同时记住滑动的是ViewGroup,子View只是间接滑动的。
最后,Scroller很简单,Scroller更类似于动画中的插值器,处理计算和存储坐标值,什么也没有做。当我们调用
mScroller.startScroll(getScrollX(),getScrollY(),0,mHeaderHeight+getPaddingTop(),3000);
后,实际上是在其中根据时间和要移动的像素计算出每一时刻所应该在的像素位置,然后不停的调用scrollBy移动到这个位置并重绘。同时由于View在重绘时绘调用computeScroll方法,所以我们要在其中进行判断并继续scroll,形成有条件递归,形成动画。
下拉刷新组件的简单原理
基本介绍
一个典型的下拉刷新界面如上,对于下拉刷新功能而言,界面主要包含两个部分,一个是展示Refresh界面的部分,一个是展示如ListView之类列表的部分。为了实现下拉刷新功能,我们所需要的就是自定义一个ViewGroup。我们的RefreshLayout中包含两个子View,header和content。header界面如下:
content可以是ListView,同样也是一个ViewGroup。界面初始时由于header和content都可以看到,所以我们在RefreshLayout的onLayout方法结束前,调用scrollTo(0,headerHeight)可以将header滑动出界面。然后,总的思路就是分析RefreshLayout和ListView对于一个触摸事件,谁来拦截谁来处理的问题。
RefreshLayout实现:
RefreshLayout绘制过程:
首先通过 LayoutInflater.from(context).inflate以及addView方法,在RefreshLayout构造函数中向布局添加header和content。对于一个ViewGroup而言,绘制过程中最重要的是onMeasure和onLayout方法。
onMeasure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = 0;
for(int i=0;i<getChildCount();i++) {
measureChild(getChildAt(i),widthMeasureSpec,heightMeasureSpec);
height += getChildAt(i).getMeasuredHeight();
}
height = heightMeasureSpec;
setMeasuredDimension(width,height);
}
onMeasure方法中,一定要对全部子View进行measure,在这里调用的是measureChild方法,因为measureChild内部还会根据子View的LayoutParams进一步封装出MeasureSpec进行测量。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
int left =getPaddingLeft();
Log.d("TAG", l + " " + t + " " + r + " " + b);
int top = getPaddingTop();
for(int i=0;i<count;i++) {
View child = getChildAt(i);
child.layout(left,top,child.getMeasuredWidth(),child.getMeasuredHeight() + top);
Log.d("TAG", "child: " + child.getMeasuredWidth() + " " + child.getMeasuredHeight());
top += child.getMeasuredHeight();
}
if(!init){
//将ViewGroup向y轴正方向移动,其实相当于将View向y轴负方向移动
scrollTo(0,mHeaderHeight+getPaddingTop());
invalidate();
init = true;
}
}
onLayout方法中进行我们想要的布局,注意由于重新绘制时,onMeasure和onLayout会多次被调用,所以要注意一些初始化方法的执行。
RefreshLayout事件拦截及处理
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
prevY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int delY = (int) (ev.getRawY() - prevY);
Log.d("TAG", "delY " + delY);
if(delY>0) {
return true;
}
break;
}
return false;
}
在拦截事件中,只做了一个简单的判断,一旦滑动的纵向距离大于0,表明手指再从上向下滑,同时这里应该判断一下ListView中显示的第一条是不是全部数据中的第一条。然后拦截事件后交由onTouchEvent处理。
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
int dy = (int) (event.getRawY() - prevY);
int sy = mHeaderHeight-dy;
scrollTo(0,sy>0?sy:0);
Log.d("TAG", "dy " + dy);
break;
case MotionEvent.ACTION_UP:
refresh();
break;
}
return true;
}
之前将ViewGroup向下滑动了headerHeight的距离,为了让header显示出来,其实应该让ViewGroup向上滑动也即y轴变小,同时为了避免过分滑动还要进行一下判断。当手指抬起时,还要根据移动的y轴增量判断一下是否是有效的滑动,然后处理响应的业务逻辑。注意的是,由于当前是主线程,所以要使用
new Thread(new Runnable() {
@Override
public void run() {
mission();
post(new Runnable() {
@Override
public void run() {
mScroller.startScroll(getScrollX(),getScrollY(),0,mHeaderHeight+getPaddingTop(),3000);
mArrowView.setVisibility(VISIBLE);
mProgress.setVisibility(GONE);
}
});
}
}).start();
新起一个线程完成mission,同时通过当前ViewGroup的消息队列,在任务完成后修改UI。
涉及到的原理大致就是这些,完整的代码可以查看何洪洋老师的博客:
https://github.com/hehonghui/android_my_pull_refresh_view
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Android
# Scroller
# 下拉刷新
# Android使用Scroller实现弹性滑动效果
# Android自定义View弹性滑动Scroller详解
# Android用Scroller实现一个可向上滑动的底部导航栏
# 详解Android应用开发中Scroller类的屏幕滑动功能运用
# android使用 ScrollerView 实现 可上下滚动的分类栏实例
# 深入理解Android中Scroller的滚动原理
# Android程序开发之UIScrollerView里有两个tableView
# Android Scroller完全解析
# Android Scroller大揭秘
# android开发通过Scroller实现过渡滑动效果操作示例
# 的是
# 要注意
# 自定义
# 谁来
# 第一条
# 会再
# 递归
# 装出
# 是在
# 在这里
# 才是
# 才会
# 还会
# 要在
# 去找
# 很简单
# 如果没有
# 可以看到
# 三种
# 相关联
相关文章:
如何快速生成ASP一键建站模板并优化安全性?
如何在VPS电脑上快速搭建网站?
建站之星上传入口如何快速找到?
html制作网站的步骤有哪些,iapp如何添加网页?
宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
完全自定义免费建站平台:主题模板在线生成一站式服务
湖州网站制作公司有哪些,浙江中蓝新能源公司官网?
再谈Python中的字符串与字符编码(推荐)
外汇网站制作流程,如何在工商银行网站上做外汇买卖?
如何在七牛云存储上搭建网站并设置自定义域名?
Python路径拼接规范_跨平台处理说明【指导】
网站制作多少钱一个,建一个论坛网站大约需要多少钱?
建站之星后台管理:高效配置与模板优化提升用户体验
Python文件管理规范_工程实践说明【指导】
Python多线程使用规范_线程安全解析【教程】
如何选择香港主机高效搭建外贸独立站?
c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】
C#如何使用XPathNavigator高效查询XML
一键制作网站软件下载安装,一键自动采集网页文档制作步骤?
制作网站建设的公司有哪些,网站建设比较好的公司都有哪些?
建站VPS推荐:2025年高性能服务器配置指南
公司门户网站制作流程,华为官网怎么做?
公司网站建设制作费用,想建设一个属于自己的企业网站,该如何去做?
建设网站制作价格,怎样建立自己的公司网站?
C++如何将C风格字符串(char*)转换为std::string?(代码示例)
宝塔建站助手安装配置与建站模板使用全流程解析
济南企业网站制作公司,济南社保单位网上缴费步骤?
C#如何在一个XML文件中查找并替换文本内容
如何用西部建站助手快速创建专业网站?
建站之星如何快速更换网站模板?
javascript中的try catch异常捕获机制用法分析
香港服务器建站指南:免备案优势与SEO优化技巧全解析
网站企业制作流程,用什么语言做企业网站比较好?
建站之星如何防范黑客攻击与数据泄露?
韩国服务器如何优化跨境访问实现高效连接?
,石家庄四十八中学官网?
如何用AWS免费套餐快速搭建高效网站?
公司网站设计制作厂家,怎么创建自己的一个网站?
建站之星与建站宝盒如何选择最佳方案?
购物网站制作公司有哪些,哪个购物网站比较好?
音乐网站服务器如何优化API响应速度?
香港服务器选型指南:免备案配置与高效建站方案解析
如何在万网ECS上快速搭建专属网站?
如何用虚拟主机快速搭建网站?详细步骤解析
家庭服务器如何搭建个人网站?
西安大型网站制作公司,西安招聘网站最好的是哪个?
如何在Windows环境下新建FTP站点并设置权限?
武汉网站如何制作,黄黄高铁武穴北站途经哪些村庄?
网站按钮制作软件,如何实现网页中按钮的自动点击?
*请认真填写需求信息,我们会在24小时内与您取得联系。