zoukankan      html  css  js  c++  java
  • UIView 中的控件事件穿透 Passthrough 的实现

    我们在有多个 UIView 层叠时,比如一个按钮被一个 UIView 遮盖时,想要在点击最上层的 UIView 时能触发按钮的相应事件,我们该如何实现呢,初步可以想到几种办法:

    1. 把按钮上层的所有 UIView 的 userInteractionEnabled 属性设置为 NO,要是 UIView 有自己的交互事件该如何办呢?而且这个 userInteractionEnabled 不能动态设置,等到点击后决定设置它的 NO 是没用的

    2. UIView 接受到点击事件后主动去触发下面按钮的点击,这时的关题有三,按钮没有点击过程中的交换效果、多层 UIView 时不切实际,逐层下传吗、还有就是其他双击、三击或别的手势如何处理

    我也一直被前面两种方式纠缠着,同时也让 UIPopoverController 的 NSArray *passthroughViews 属性提醒着,因为对于 UIPopoverController,设置到它的 passthoughViews 属性中的控件事件可以完全从 UIDimmingView 下透出来。但苦于不可能看到 UIPopoverController 的源码,还是后面一而再的 Google 终于发现了 UIView 的方法:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system

    只要实现了最顶层的 UIView 的 hitTest 方法,在某些情况返回下层的某个按钮实例,即相当于把那个按钮的事件透出来了,比如在点击落在该按钮上时,不管这个按钮在 UIView 下多少层都可以把它挖出来。

    先看效果图:

      

    三个图分别是:

    1. 所见到的,按钮被半透明红色 View 遮住了一部分
    2. 可点击未遮住的按钮部分,可看到按钮被点下未抬起的效果
    3. 在红色的 View 中点击按钮被遮住部分,同样触发了按钮的相应事件,且有中间效果,也就是说按钮穿透出来了

    再看代码实现,有两部分代码,分别是 ViewController 和  CustomController

    ViewController.h

     
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    //
    //  ViewController.h
     
    //
    //  Created by Unmi on 11/15/11.
    //  Copyright (c) 2011 http://unmi.cc. All rights reserved.
    //
     
    #import <UIKit/UIKit.h>
     
    @interface ViewController : UIViewController{
    }
     
    @end

    ViewController.h

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    //
    //  ViewController.m
    //
    //  Created by Unmi on 11/15/11.
    //  Copyright (c) 2011 http://unmi.cc. All rights reserved.
    //
     
    #import "ViewController.h"
    #import "CustomView.h"
     
    @implementation ViewController{
        UIButton *passthroughButton;
    }
     
    #pragma mark - View lifecycle
     
    - (void)viewDidLoad
    {
        [super viewDidLoad];
     
        passthroughButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [passthroughButton setTitle:@"Passthrough" forState:UIControlStateNormal];
        [self.view addSubview:passthroughButton];
        passthroughButton.frame = CGRectMake(20, 50, 120, 28);
        [passthroughButton release];
         
        CustomView *customView = [[CustomView alloc] initWithFrame:CGRectMake(80, 10, 300, 200)];
        customView.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:.5];
        customView.passthroughViews = [NSArray arrayWithObject:passthroughButton];
        [self.view addSubview:customView];
        [customView release];
    }
     
    - (void)dealloc {
        [super dealloc];
    }
    @end

    CustomView.h

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    //
    //  CustomView.h
    //  TestPopover
    //
    //  Created by Unmi on 2/19/12.
    //  Copyright (c) 2012 http://unmi.cc. All rights reserved.
    //
     
    #import <UIKit/UIKit.h>
     
    @interface CustomView : UIView
    @property (nonatomic, copy) NSArray *passthroughViews;
    @end

    CustomView.m

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    //
    //  CustomView.m
    //
    //  Created by Unmi on 2/19/12.
    //  Copyright (c) 2012 http://unmi.cc. All rights reserved.
    //
     
    #import "CustomView.h"
     
    @interface CustomView()
    -(BOOL) isPassthroughView: (UIView*) view;
    @end
     
    @implementation CustomView{
        BOOL testHits;
    }
     
    @synthesize passthroughViews=_passthroughViews;
     
    -(UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event{
        if(testHits){
            return nil;
        }
         
        if(!self.passthroughViews
            || (self.passthroughViews && self.passthroughViews.count == 0)){
            return self;
        } else {
             
            UIView *hitView = [super hitTest:point withEvent:event];
             
            if (hitView == self) {
                //Test whether any of the passthrough views would handle this touch
                testHits = YES;
                CGPoint superPoint = [self.superview convertPoint:point fromView:self];
                UIView *superHitView = [self.superview hitTest:superPoint withEvent:event];
                testHits = NO;
                 
                if ([self isPassthroughView:superHitView]) {
                    hitView = superHitView;
                }
            }
             
            return hitView;
        }
    }
     
    - (BOOL)isPassthroughView:(UIView *)view {
         
        if (view == nil) {
            return NO;
        }
         
        if ([self.passthroughViews containsObject:view]) {
            return YES;
        }
         
        return [self isPassthroughView:view.superview];
    }             
     
    -(void) dealloc{
        self.passthroughViews = nil;
    }
     
    @end

    关键要理解 hitTest 方法的作用,可参考:

    1. http://blog.sina.com.cn/s/blog_677089db01012wpg.html
    2. https://github.com/werner77/WEPopover

     
     
  • 相关阅读:
    【每日一学】pandas_透视表函数&交叉表函数
    【Excel技能】字符串包含某字符串个数?替换许多组字符串?
    【SQL函数】我知道你想group_concat和count一起用,比如不同组合的人数?
    mysql大纲
    【Excel】绘图案例_常见复合图:簇状图+堆积图+折线图
    【统计分析方法】1.统计学知识图谱
    【统计分析方法】知识图谱(主要是统计推断部分)
    python之前期常用的内置函数
    python之匿名函数,函数递归
    python之三元表达式、列表生成式、字典表达式、生成器表达式
  • 原文地址:https://www.cnblogs.com/superchao8/p/2697263.html
Copyright © 2011-2022 走看看