如何实现点击ios uiview点击效果上任意位置触发事件

/** 获取到事件中点击的视图用来判断当前点击 */- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{& & /** 获取事件event中的触发视图 */& & UIView *hitView = [superhitTest:point withEvent:event];& & /** 判断是否当前视图 */& & if (hitView ==self) {& & & & returnnil;& & } else {& & & & return hitV& & }}/** 判断是否是当前视图触发的事件 */- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{& & return [superpointInside:point withEvent:event];}/** 将一个坐标点转换成指定view的坐标 */- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view{& & return [superconvertPoint:point toView:view];}/** 将一个坐标点转换成当前view的坐标 */- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view{& & return [superconvertPoint:point fromView:view];}/** 将一个CGRect转换成指定view的CGRect */- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view{& & return [superconvertRect:rect toView:view];}/** 讲一个CGRect转换成当前view的CGRect */- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view{& & return [superconvertRect:rect fromView:view];}/** 获取适合label内容的CGSize */- (CGSize)sizeThatFits:(CGSize)size{& & return [supersizeThatFits:size];}/** 自动设置适合内容的CGSize */- (void)sizeToFit{& & [supersizeToFit];}/** 从父视图中移除当前视图 */- (void)removeFromSuperview{& & [superremoveFromSuperview];}/** 在index层插入一个视图 */- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index{& & [superinsertSubview:view atIndex:index];}/** 交换两个视图的图层 */- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2{& & [superexchangeSubviewAtIndex:index1 withSubviewAtIndex:index2];}/** 加入一个视图在最上一层 */- (void)addSubview:(UIView *)view{& & [superaddSubview:view];}/** 在siblingSubview视图下面插入一个视图 */- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview{& & [superinsertSubview:view belowSubview:siblingSubview];}/** 在siblingSubview视图上面插入一个视图 */- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview{& & [superinsertSubview:view aboveSubview:siblingSubview];}/** 将一个视图放到最上一层 */- (void)bringSubviewToFront:(UIView *)view{& & [superbringSubviewToFront:view];}/** 将一个视图推送到最下层 */- (void)sendSubviewToBack:(UIView *)view{& & [supersendSubviewToBack:view];}/** 添加子视图时调用 */- (void)didAddSubview:(UIView *){& & [superdidAddSubview:subview];& & NSLog(@&添加子视图&);}/** 将要移除子视图时调用 */- (void)willRemoveSubview:(UIView *)subview{& & [superwillRemoveSubview:subview];& & NSLog(@&移除子视图&);}/** 父视图将要发生更改时调用 */- (void)willMoveToSuperview:(UIView *)newSuperview{& & [superwillMoveToSuperview:newSuperview];& & NSLog(@&父视图将要发生更改&);}/** 父视图更改时调用 */- (void)didMoveToSuperview{& & [superdidMoveToSuperview];& & NSLog(@&父视图发生更改&);}/** 视图或其超视图将要展示到窗口调用 */- (void)willMoveToWindow:(UIWindow *)newWindow{& & [superwillMoveToWindow:newWindow];& & NSLog(@&视图展示到窗口&);}/** 视图或其超视图展示到窗口调用 */- (void)didMoveToWindow{& & [superdidMoveToSuperview];& & NSLog(@&视图或其超视图展示到窗口&);}/** 判断当前视图是否是指定视图或者其子视图 */- (BOOL)isDescendantOfView:(UIView *)view{& & return [superisDescendantOfView:view];}/** 获取当前视图内指定tag值的视图 */- (UIView *)viewWithTag:(NSInteger)tag{& & return [superviewWithTag:tag];}/** 在图层绘制时调用的方法 */- (void)setNeedsLayout{&& &}- (void)layoutIfNeeded{&& &}/** 当视图上的图层发生改变时调用 */- (void)layoutSubviews{&& &}/** 发生自动布局时调用 */- (void)layoutMarginsDidChange{&& &}/** 绘制图层layer时调用 */- (void)drawRect:(CGRect)rect{&& &}/** 重绘图层 */- (void)setNeedsDisplay{&& &}/** 重绘图层指定范围 */- (void)setNeedsDisplayInRect:(CGRect)rect{& &}/** tintColor 是一种有抛光效果的设置视图颜色 *//** tintColor改变时调用 */- (void)tintColorDidChange{&& &}#pragma mark - 动画相关/** 开启动画块 animationID动画标示 context参数 */+ (void)beginAnimations:(NSString *)animationID context:(void *)context{& & [superbeginAnimations:animationID context:context];}/** 提交动画块动画开始执行 */+ (void)commitAnimations{& & [supercommitAnimations];}/** 设置动画代理 */+ (void)setAnimationDelegate:(id)delegate{& & [supersetAnimationDelegate:delegate];}/** 当动画开始时发送一个消息给动画代理 */+ (void)setAnimationWillStartSelector:(SEL)selector{& & [supersetAnimationWillStartSelector:selector];& & /** 动画代理执行selector方法 */}/** 当动画结束时发送一个消息给动画代理 */+ (void)setAnimationDidStopSelector:(SEL)selector{& & [supersetAnimationDidStopSelector:selector];& & /** 动画代理执行selector方法 */}/** 设置动画时长默认0.2s */+ (void)setAnimationDuration:(NSTimeInterval)duration{& & [supersetAnimationDuration:duration];}/** 设置动画执行延迟时长默认0s */+ (void)setAnimationDelay:(NSTimeInterval)delay{& & [supersetAnimationDelay:delay];}/** 设置动画开始时间NSDate */+ (void)setAnimationStartDate:(NSDate *)startDate{& & [supersetAnimationStartDate:startDate];}/** 设置动画的曲线方式(就是动画的总体变化的时间曲线:开始快最后慢,开始慢最后快,最后慢,均匀线性)。&& & curve参数如下:&& & typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {& & UIViewAnimationCurveEaseInOut, & & & & // slow at beginning and end& & UIViewAnimationCurveEaseIn,& & & & & & // slow at beginning& & UIViewAnimationCurveEaseOut, & & & & & // slow at end& & UIViewAnimationCurveLinear& & };&&*/+ (void)setAnimationCurve:(UIViewAnimationCurve)curve{& & [supersetAnimationCurve:curve];}/** 设置动画重复次数 */+ (void)setAnimationRepeatCount:(float)repeatCount{& & [supersetAnimationRepeatCount:repeatCount];}/** && & 设置动画是否做一次反向的执行。& & 如果设置为YES:动画将执行:动画初始状态》动画》动画完成状态》动画》动画初始状态。& & 如果设置为NO:默认值&&*/+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses{& & [supersetAnimationRepeatAutoreverses:repeatAutoreverses];}/** 设置动画开始时状态&当YES时:当上一次动画正在执行中,那么当下一个动画开始时,上一次动画的当前状态将成为下一次动画的开始状态。&当NO时:当上一个动画正在执行中,那么当下一个动画开始时,上一次动画需要先恢复到完成时的状态,然后在开始执行下一次动画。&*/+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState{&& &}/** 添加动画到视图view上 transition动画样式 cache为YES时高效 但动画执行过程中不能更新UI为NO时每一帧都可以重新绘制 可以实时更新UI */+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache{&& &}/** 是否支持动画默认YES */+ (void)setAnimationsEnabled:(BOOL)enabled{&& &}/** 返回动画效果是否被禁用 */+ (BOOL)areAnimationsEnabled{& & return [superareAnimationsEnabled];}/** 强制一些动作不使用动画我也不懂 测出来再补上 */+ (void)performWithoutAnimation:(void (^)(void))actionsWithoutAnimation{&& &}#pragma mark - 动画Block块/**&duration & 执行时长&delay& & & 延迟时长&options& & 动画执行曲线&animations 动画动作Block&completion 动画执行完毕后执行的Block&*/+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion {&& &}/**&duration & 执行时长&animations 动画动作Block&completion 动画执行完毕后执行的Block&*/+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion {&& &}/**&&duration & 执行时长&animations 动画动作Block&*/+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations {&& &}/**&&SpringAnimation动画干净 快速&usingSpringWithDamping 0~1 弹簧效果越小弹簧效果越明显&&initialSpringVelocity& 初始速度初始速度取值较高而时间较短时 也会出现弹簧效果&*/+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion {&& &}/**&&过场动画&duration & 动画时长&view & & & 进行转场动画的视图&options& & 专场动画类型&animations 执行动画&completion 动画结束后调用的Block&*/+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion {&& &}/**&过场动画&[fromView.superview addSubview:toView];&[fromView.superview removeFromSuperview];&*/+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion {&& &}/**&在一组视图上执行指定的系统动画,并可以并行自定义的动画&parallelAnimations就是与系统动画并行的自定义动画&*/+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray *)views options:(UIViewAnimationOptions)options animations:(void (^)(void))parallelAnimations completion:(void (^)(BOOL finished))completion {&& &}#pragma mark - UIViewKeyframeAnimations/**&&关键帧动画&duration & 动画时长&delay& & & 动画延迟&options& & 动画效果选项&animations 动画执行代码&completion 动画结束执行代码&*/+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion {&& &}/**&frameStartTime 动画相对开始时间&frameDuration& 动画相对持续时间&自身会根据动画总持续时长自动匹配其运行时长&*/+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations {&& &}#pragma mark - 手势/** 添加手势 */- (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer {&& &}/** 移除手势 */- (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer {&& &}/** 是否执行该手势 */- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {& & returnYES;}/** 添加运动拟真效果 *//** UIMotionEffect 运动拟真效果类物理效果 */- (void)addMotionEffect:(UIMotionEffect *)effect {&& &}/** 移除运动拟真效果 */- (void)removeMotionEffect:(UIMotionEffect *)effect {&& &}#pragma mark - 约束自动布局/** 只知道是自动布局相关但是具体效果 未知查不到 测不出==! */- (NSArray *)constraints {& & return [superconstraints];}/** 添加约束需要先开启自动布局 */- (void)addConstraint:(NSLayoutConstraint *)constraint {&& &}/** 添加约束 */- (void)addConstraints:(NSArray *)constraints {&& &}/** 移除约束 */- (void)removeConstraint:(NSLayoutConstraint *)constraint {&& &}/** 移除约束 */- (void)removeConstraints:(NSArray *)constraints {&& &}/** 更新视图和其子视图的约束 */- (void)updateConstraintsIfNeeded {&& &}/** 更新视图和其子视图的约束 */- (void)updateConstraints {&& &}/** 是否更新视图的约束 */- (BOOL)needsUpdateConstraints {& & return [superneedsUpdateConstraints];}/** 设置视图的约束需要更新 */- (void)setNeedsUpdateConstraints {&& &}/** 是否关闭自动布局 */- (BOOL)translatesAutoresizingMaskIntoConstraints {& & return [supertranslatesAutoresizingMaskIntoConstraints];}/** 是否关闭自动布局 */- (void)setTranslatesAutoresizingMaskIntoConstraints:(BOOL)flag {&& &}/** 是否支持自动布局 */+ (BOOL)requiresConstraintBasedLayout {& & return [superrequiresConstraintBasedLayout];}/** 返回给定框架的视图的对齐矩阵 */- (CGRect)alignmentRectForFrame:(CGRect)frame {& & return [superalignmentRectForFrame:frame];}/** 返回给定对齐矩形的视图的frame& */- (CGRect)frameForAlignmentRect:(CGRect)alignmentRect {& & return [superframeForAlignmentRect:alignmentRect];}/** 对当前View设置用来布局的矩形设置偏移 */- (UIEdgeInsets)alignmentRectInsets {& & return [superalignmentRectInsets];}/** 默认返回当前视图的底部作为baseline。我们可以重写上述方法,但必须返回的是当前视图中的子视图 */- (UIView *)viewForBaselineLayout {& & return [superviewForBaselineLayout];}/** 通过重写intrinsicContentSize可以设置当前视图显示特定内容时的大小 */- (CGSize)intrinsicContentSize {& & CGSize size = [superintrinsicContentSize];& & if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {& & & & size.width +=4.0f;& & } else {& & & & size.width +=40.0f;& & }&& && & if (self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {& & & & size.height +=4.0;& & } else {& & & & size.height +=40.0;& & }&& && & return}/** 视图根据内部内容设置Size */- (void)invalidateIntrinsicContentSize {& & [superinvalidateIntrinsicContentSize];}- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis {& & return [supercontentHuggingPriorityForAxis:axis];}/** 使其在“内容大小”的基础上不能继续变大 */- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis {&& &}- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis {& & return [supercontentCompressionResistancePriorityForAxis:axis];}/** 使其在在其“内容大小”的基础上不能继续变小 */- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis {&& &}/** 动态计算控件的Size targetSize可传参数:UILayoutFittingCompressedSize最小情况下可能的Size UILayoutFittingExpandedSize最大情况下可能的Size */- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize {& & return [supersystemLayoutSizeFittingSize:targetSize];}/** 动态计算控件的Size UILayoutPriority优先级&& & horizontalFittingPriority & 水平约束优先级& & verticalFittingPriority & & 垂直约束优先级 */- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {& & return [supersystemLayoutSizeFittingSize:targetSizewithHorizontalFittingPriority:horizontalFittingPriorityverticalFittingPriority:verticalFittingPriority];}/** 约束检查为什么这个View 这样显返回值 约束条件 */- (NSArray *)constraintsAffectingLayoutForAxis:(UILayoutConstraintAxis)axis {& & return [superconstraintsAffectingLayoutForAxis:axis];}/** 判断当前的自动布局约束是否还有其他满足约束的条件 */- (BOOL)hasAmbiguousLayout {& & return [superhasAmbiguousLayout];}/** 随机实现一个满足约束的条件 */- (void)exerciseAmbiguityInLayout {&& &}#pragma mark - NSCoder/** 归档时编码 */- (void) encodeRestorableStateWithCoder:(NSCoder *)coder {&& &}/** 反归档时解码 */- (void) decodeRestorableStateWithCoder:(NSCoder *)coder {&& &}/** 复制一个复合视图& & afterUpdates& & 是否视图展示时才生成视图& & No& & & & & & & 会立即生成快照,并不会调用重新设置颜色的方法无色& & YES & & & & & & 当调用这个视图时生成&*/- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates {& & return [supersnapshotViewAfterScreenUpdates:afterUpdates];}/** 复制一个指定范围偏移量的复合视图 */- (UIView *)resizableSnapshotViewFromRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates withCapInsets:(UIEdgeInsets)capInsets {& & return [superresizableSnapshotViewFromRect:rectafterScreenUpdates:YESwithCapInsets:capInsets];}/** 将指定范围的视图绘制到图形上下文中 */- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates {& & return [superdrawViewHierarchyInRect:rect afterScreenUpdates:afterUpdates];}iOS UIView事件隔层传递 pointInside:withEvent:
多层视图重叠跳过中间层,实现隔层视图事件响应
DataViewController.m
UIScrollViewPanGesture
Created by Peace on 11/17/15.
Copyright & 2015 Peace. All rights reserved.
#import &DataViewController.h&
@interface TestView1 : UIView
@implementation TestView1
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
CGRect frame = CGRectMake(0, 0,
self.frame.size.width,
self.frame.size.height);
BOOL value = (CGRectContainsPoint(frame, point));
NSArray *views = [self subviews];
for (UIView *subview in views) {
value = (CGRectContainsPoint(subview.frame, point));
if (value) {
return NO;
- (void)touchesBegan:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
NSLog(@&1:xxxx&);
- (void)touchesEnded:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
NSLog(@&1:yyyy&);
@interface TestView2 : UIView
@implementation TestView2
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
CGRect frame = CGRectMake(0, 0,
self.frame.size.width,
self.frame.size.height);
BOOL value = (CGRectContainsPoint(frame, point));
- (void)touchesBegan:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
NSLog(@&2:xxxx&);
- (void)touchesEnded:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
NSLog(@&2:yyyy&);
* ViewController
@interface DataViewController ()
@implementation DataViewController
- (void)viewDidLoad
[super viewDidLoad];
//白色视图接受点击事件
self.view.backgroundColor = [UIColor whiteColor];
//红色视图(****注:不接受点击事件****)
TestView1 *v1 = [[TestView1 alloc] initWithFrame:CGRectMake(50.f, 50.f, 200.f, 200.f)];
v1.backgroundColor = UIColor.redC
[self.view addSubview:v1];
//黄色视图接受点击事件
TestView2 *v2 = [[TestView2 alloc] initWithFrame:CGRectMake(0.f, 0.f, 100.f, 100.f)];
v2.backgroundColor = UIColor.yellowC
[v1 addSubview:v2];
- (void)touchesBegan:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
NSLog(@&3:xxxx&);
- (void)touchesEnded:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
NSLog(@&3:yyyy&);
顶一下(0) 踩一下(0)
热门标签:来源:网络 && 编辑:adminStay hungry
主要是记录下iOS的界面触摸事件处理机制,然后用一个实例来说明下应用场景.
一、处理机制
界面响应消息机制分两块,(1)首先在视图的层次结构里找到能响应消息的那个视图。(2)然后在找到的视图里处理消息。
【关键】(1)的过程是从父View到子View查找,而(2)是从找到的那个子View往父View回溯(不一定会往回传递消息)。
1.1、寻找响应消息视图的过程可以借用M了个J的一张图来说明。
处理原理如下:
& 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中
&&UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)
&&主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件
(hitTest:withEvent:其实是UIView的一个方法,UIWindow继承自UIView,因此主窗口UIWindow也是属于视图的一种)
&&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:方法返回的视图对象去处理。
拿到这个UIView后,就调用该UIView的touches系列方法。
1.2、消息处理过程,在找到的那个视图里处理,处理完后根据需要,利用响应链nextResponder可将消息往下一个响应者传递。
UIAppliactionDelegate &- UIWindow &- UIViewController &- UIView &- UIView
【关键】:要理解的有三点:1、iOS判断哪个界面能接受消息是从View层级结构的父View向子View传递,即树状结构的根节点向叶子节点递归传递。2、hitTest和pointInside成对,且hitTest会调用pointInside。3、iOS的消息处理是,当消息被人处理后默认不再向父层传递。
二、应用实例
【需求】是:界面如下,
  -ViewA
    -ButtonA
    -ViewB
      -ButtonB
层次结构:ViewB完全盖住了ButtonA,ButtonB在ViewB上,现在需要实现1)ButtonA和ButtonB都能响应消息 2)ViewA也能收到ViewB所收到的touches消息 3)不让ViewB(ButtonB)收到消息。
(首先解析下,默认情况下,点击了ButtonB的区域,iOS消息处理过程。
  -ButtonA
  -ViewB
    -ButtonB
当点击ButtonB区域后,处理过程:从ViewA开始依次调用hitTest
pointInside的值依次为:
ViewA:NO;
ViewB:YES;
ButtonB:YES;
ButtonB的subViews:NO;
所以ButtonB的subViews的hitTest都返回nil,于是返回的处理对象是ButtonB自己。接下去开始处理touches系列方法,这里是调用ButtonB绑定的方法。处理完后消息就停止,整个过程结束。)
【分析】:
实现的方式多种,这里将两个需求拆解开来实现,因为实现2就可以满足1。
2.1、需求1的实现,ViewB盖住了ButtonA,所以默认情况下ButtonA收不到消息,但是在消息机制里寻找消息响应是从父View开始,所以我们可以在ViewA的hitTest方法里做判断,若touch point是在ButtonA上,则将ButtonA作为消息处理对象返回。
代码如下:
#pragma mark - hitTest
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
// 当touch point是在_btn上,则hitTest返回_btn
CGPoint btnPointInA = [_btn convertPoint:point fromView:self];
if ([_btn pointInside:btnPointInA withEvent:event]) {
// 否则,返回默认处理
return [super hitTest:point withEvent:event];
这样,当触碰点是在ButtonA上时,则touch消息就被拦截在ViewA上,ViewB就收不到了。然后ButtonA就收到touch消息,会触发onClick方法。
2.2、需求2的实现,上面说到响应链,ViewB只要override掉touches系列的方法,然后在自己处理完后,将消息传递给下一个响应者(即父View即ViewA)。
代码如下:在ViewB代码里
#pragma mark - touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"B - touchesBeagan..");
// 把事件传递下去给父View或包含他的ViewController
[self.nextResponder touchesBegan:touches withEvent:event];
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"B - touchesCancelled..");
// 把事件传递下去给父View或包含他的ViewController
[self.nextResponder touchesBegan:touches withEvent:event];
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"B - touchesEnded..");
// 把事件传递下去给父View或包含他的ViewController
[self.nextResponder touchesBegan:touches withEvent:event];
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"B - touchesMoved..");
// 把事件传递下去给父View或包含他的ViewController
[self.nextResponder touchesBegan:touches withEvent:event];
然后,在ViewA上就可以接收到touches消息,在ViewA上写:
#pragma mark - touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"A - touchesBeagan..");
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"A - touchesCancelled..");
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"A - touchesEnded..");
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
NSLog(@"A - touchesMoved..");
这样就实现了向父View透传消息。
2.3 、不让ViewB收到消息,可以设置ViewB.UserInteractionEnable=NO;除了这样还可以override掉ViewB的ponitInside,原理参考上面。
在ViewB上写:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
// 本View不响应用户事件
return NO;
阅读(...) 评论()

我要回帖

更多关于 uiview不响应点击事件 的文章

 

随机推荐