UIview使用pointInside方法

时间:2013-03-16 22:15:10

标签: ios xcode

我正在创建一个UIview并以这种方式在其上应用蒙版:

baseView = [[ViewTutorialSubclass alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
//self.view = baseView;
[self.view addSubview:baseView];
[baseView setBackgroundColor:[UIColor blackColor]];
baseView.userInteractionEnabled = YES;
baseView.alpha = 0.7;

mask = [[CAShapeLayer alloc] init];
mask.frame = baseView.layer.bounds;
CGRect biggerRect = CGRectMake(mask.frame.origin.x, mask.frame.origin.y, mask.frame.size.width, mask.frame.size.height);
CGRect smallerRect = CGRectMake(7.0f, 160.0f, 590.0f, 43.0f);

UIBezierPath *maskPath = [UIBezierPath bezierPath];
[maskPath moveToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMaxY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMaxY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMinY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))];

[maskPath moveToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMaxY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMaxY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMinY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))];

mask.path = maskPath.CGPath;
[mask setFillRule:kCAFillRuleEvenOdd];
mask.fillColor = [[UIColor blackColor] CGColor];
baseView.layer.mask = mask;

在我的ViewTutorialSubclass.m中,我有:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
for (UIView *v in self.subviews) {
    CGPoint localPoint = [v convertPoint:point fromView:self];
    if (v.alpha > 0.8 && [v pointInside:localPoint withEvent:event])
        return YES;
}
return NO;
}

如果用户使用蒙版触摸UIview的任何部分(如此透明),则所有用户触摸都会传递到此视图下方的UIview,而如果用户触摸其他任何位置,则触摸将应用于此当前UIView的。我该怎么办? pointInside是最好的解决方案吗?

1 个答案:

答案 0 :(得分:3)

包含遮罩层的视图类应覆盖pointInside,并根据遮罩状态返回YES或NO。如果蒙版始终是一个矩形,那么你可以在矩形测试中做一个点,但我打赌这不是你想要的。您希望此测试适用于任意形状的蒙版。设置(在dispatch_once中)一个像素宽的CGBitmapContext。在pointInside中:withEvent:将遮罩层渲染到位图上下文中,看看它是否绘制了任何东西。这是一个例子:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    static CGContextRef context;
    static CGColorSpaceRef rgbColorSpace;
    static unsigned char bitmapData[4];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        rgbColorSpace = CGColorSpaceCreateDeviceRGB();
        context = CGBitmapContextCreate(bitmapData, 1, 1, 8, 4, rgbColorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
    });
    if ([super pointInside:point withEvent:event]) {
        CGContextTranslateCTM(context, -point.x, -point.y);
        [self.layer.mask renderInContext:context];
        CGContextTranslateCTM(context, point.x, point.y);
        BOOL result = (bitmapData[3] > 0);
        memset(bitmapData, 0, sizeof(bitmapData));
        return result;
    }
    return NO;
}

编辑:如果将kCGImageAlphaPremultipliedLast(单独)传递给CGBitmapContextCreate,Xcode 5中的编译器会生成有关枚举类型不匹配的警告。参数的类型应为CGBitmapInfo,但kCGImageAlphaPremultipliedLast来自枚举类型CGImageAlphaInfo。要消除警告,您可以将kCGImageAlphaPremultipliedLastCGBitmapInfo枚举类型中的值结合使用,例如kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast。无论如何这样做更好,因为新代码明确表示我们正在发送一般的“位图信息”,但我们感兴趣的是位图信息与alpha通道的处理方式有关。