事件分发机制Hit-Test View的应用(TabBar凸起不能点击解决方法)

一、事件分发原理

--- hitTest:withEvent:方法大致处理流程是这样的:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:
-- 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil
-- 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:
-- 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束
-- 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self)
-- 最终,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理

? hitTest:withEvent:方法会忽略以下视图:
1> 隐藏(hidden=YES)的视图
2> 禁止用户操作(userInteractionEnabled=NO)的视图
3> alpha<0.01的视图
4> 如果一个子视图的区域超过父视图的区域(如果父视图的clipsToBounds属性为NO,超过父视图区域的子视图内容也会显示),那么正常情况下在父 视图区域外的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种

综上所述可得:如果父视图的userInteractionEnabled=NO,触摸事件不会继续往下传递给子视图,所以子视图永远无法处理触摸事件。而UIImageView在默认情况下的userInteractionEnabled就是NO。

二、官方详细说明

假设我们现在点击到了图中的E,hit-testing将进行如下步骤的检测(不包含重写hit-test并且返回非默认View的情况)
1、触摸点在ViewA内,所以检查ViewA的Subview B、C
2、触摸点不在ViewB内,触摸点在ViewC内部,所以检查ViewC的Subview D、E
3、触摸点不在ViewD内,触摸点发生在ViewE内部,并且ViewE没有subview,所以ViewE属于ViewA中包含这个点的最小单位,所以ViewE变成了该次触摸事件的hit-TestView
1、默认的hit-testing顺序是按照UIView中Subviews的逆顺序
2、如果View的同级别Subview中有重叠的部分,则优先检查顶部的Subview,如果顶部的Subview返回nil, 再检查底部的Subview
3、Hit-Test也是比较聪明的,检测过程中有这么一点,就是说如果点击没有发生在某View中,那么该事件就不可能发生在View的Subview中,所以检测过程中发现该事件不在ViewB内,也直接就不会检测在不在ViewF内。也就是说,如果你的Subview设置了clipsToBounds=NO,实际显示区域可能超出了superView的frame,你点击超出的部分,是不会处理你的事件的,就是这么任性!

三、事例

1、解决TabBar凸起部分不能点击

//重写hitTest方法,去监听发布按钮的点击,目的是为了让凸出的部分点击也有反应
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    //这一个判断是关键,当页面不显示TabBar,这个按钮还是有反应,这样就不好了
    //self.isHidden == NO 说明当前页面是有tabbar的,那么肯定是在导航控制器的根控制器页面
    //在导航控制器根控制器页面,那么我们就需要判断手指点击的位置是否在发布按钮身上
    //是的话让发布按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
    if (self.hidden == NO) {
         //将当前tabbar的触摸点转换坐标系,转换到发布按钮的身上,生成一个新的点
        CGPoint newP = [self convertPoint:point toView:self.publicButton];

             //判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
        if ([self.publicButton pointInside:newP withEvent:event]) {
            return self.publicButton;
        }else{//如果点不在发布按钮身上,直接让系统处理就可以了
            return [super hitTest:point withEvent:event];
        }
    }
 return [super hitTest:point withEvent:event];
}
时间: 2024-08-26 19:52:36

事件分发机制Hit-Test View的应用(TabBar凸起不能点击解决方法)的相关文章

Atitit View事件分发机制

1. Atitit View事件分发机制 1. Atitit View事件分发机制1 1.1. 三个关键方法 dispatchTouchEvent onInterceptTouchEvent onTouchEvent1 1.1.1. public boolean dispatchTouchEvent(MotionEvent ev)1 1.1.2. public boolean onInterceptTouchEvent(MotionEvent ev)1 1.1.3. public boolean

Android事件分发机制详解:史上最全面、最易懂

前言 Android事件分发机制是每个Android开发者必须了解的基础知识 网上有大量关于Android事件分发机制的文章,但存在一些问题:内容不全.思路不清晰.无源码分析.简单问题复杂化等等 今天,我将全面总结Android的事件分发机制,我能保证这是市面上的最全面.最清晰.最易懂的 本文秉着"结论先行.详细分析在后"的原则,即先让大家感性认识,再通过理性分析从而理解问题: 所以,请各位读者先记住结论,再往下继续看分析: 文章较长,阅读需要较长时间,建议收藏等充足时间再进行阅读 目

Android6.0触摸事件分发机制解读

本篇博文是Android触摸事件分发机制系列博文的第一篇,带领大家从全局掌握Android触摸事件分发机制.特别声明的是,本源码解读是基于最新的Android6.0版本. (一)Android6.0源码解读之View点击事件分发机制 (二)Android6.0源码解读之ViewGroup点击事件分发机制 (三)Android6.0源码解读之Activity点击事件分发机制 为什么要解读触摸事件分发机制 1.掌握View事件分发机制 2.为解决View滑动冲突提供理论支持 3.了解Android最

Android中的事件分发机制——ViewGroup的事件分发

综述 Android中的事件分发机制也就是View与ViewGroup的对事件的分发与处理.在ViewGroup的内部包含了许多View,而ViewGroup继承自View,所以ViewGroup本身也是一个View.对于事件可以通过ViewGroup下发到它的子View并交由子View进行处理,而ViewGroup本身也能够对事件做出处理.下面就来详细分析一下ViewGroup对时间的分发处理. MotionEvent 当手指接触到屏幕以后,所产生的一系列的事件中,都是由以下三种事件类型组成.

Android中的事件分发机制总结

Android 的事件分发机制 一.View的事件分发总结: View的onTouchEvent和OnTouch区别  还是以自定义的TestButton为例. 我们可以通过重写onTouchEvent方法来处理诸如down move up的消息: public class TestButton extends Button { public TestButton(Context context) { super(context); // TODO Auto-generated construc

Android面试收集录6 事件分发机制

1.基础认知 1.1.事件分发的对象是谁? 答:事件. 当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件). Touch事件相关细节(发生触摸的位置.时间.历史记录.手势动作等)被封装成MotionEvent对象 主要发生的Touch事件有如下四种: MotionEvent.ACTION_DOWN:按下View(所有事件的开始) MotionEvent.ACTION_MOVE:滑动View MotionEvent.ACTION_CANCEL:非人为原因结

Android中的事件分发机制(下)——View的事件处理

综述 在上篇文章Android中的事件分发机制(上)--ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析.在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View.并交由子View进行处理.那么现在就来分析一下子View接收到事件以后是如何处理的. View的事件处理 对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元

Android View 事件分发机制 源码解析 (上)

一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~ 首先我们先写个简单的例子来测试View的事件转发的流程~ 1.案例 为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志~ MyButton [java] view plain copy package com.example.zhy_event03; import android.content.Context; import andr

Android View的事件分发机制

准备了一阵子,一直想写一篇事件分发的文章总结一下.这个知识点实在是太重要了. 一个应用的布局是丰富的,有TextView,ImageView,Button等.这些子View的外层还有ViewGroup.如RelativeLayout.LinearLayout.作为一个开发人员,我们会思考.当点击一个button,Android系统是如何确定我点的就是button而不是TextView的?然后还正确的响应了button的点击事件. 内部经过了一系列什么过程呢? 先铺垫一些知识能更加清晰的理解事件分