2013-03-16 2 views
1

Я создаю UIView и применяя маску на него таким образом:UIView с помощью метода pointInside

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 лучшим решением?

ответ

3

Класс представления, который содержит слой маски, должен переопределять точкуInside и возвращать YES или NO в зависимости от состояния маски. Если маска всегда будет прямоугольником, вы можете сделать точку в тесте прямоугольника, но я уверен, что это не то, что вы хотите. Вы хотите, чтобы этот тест работал для маски произвольной формы. Настройте (в dispatch_once) CGBitmapContext с шириной в один пиксель. В пунктеInside: 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; 
} 

Edit: Компилятор в Xcode 5 генерирует предупреждение о перечисленном несовпадения типа, если вы передаете kCGImageAlphaPremultipliedLast (сам по себе), чтобы CGBitmapContextCreate. Тип аргумента должен быть CGBitmapInfo, но kCGImageAlphaPremultipliedLast - из перечисленного типа CGImageAlphaInfo. Чтобы устранить предупреждение, вы можете комбинировать kCGImageAlphaPremultipliedLast со значением из нумерационного типа CGBitmapInfo, например kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast. Так или иначе, так как новый код делает явным, что мы отправляем общую «информацию о растровых изображениях», но нас интересует только только в битмап-информации, относящейся к тому, как обрабатывается альфа-канал.

+0

Ответ выглядит великолепно. Вы правильно поняли, я в какой-то момент удалю маску и добавлю другую с разными размерами, но я не могу понять ваш подход к проблеме. – Alessandro

+0

Код, хотя работает отлично. Огромный ответ спасибо +1 – Alessandro

+0

@Alessandro Код в dispatch_once создает контекст чертежа, поддерживаемый одноразрядным растровым изображением. В более позднем коде применяется преобразование в контекст растрового изображения, который указывает на начало координат и рисует маску в растровое изображение. Если точка находится в прозрачной маске, тогда прозрачный пиксель, {0, 0, 0, 0}, будет нарисован в начале координат. Если точка не в маске, в начале координат будет нарисован черный полный альфа-пиксель, {0, 0, 0, 255}. Растровые пиксели хранятся в bitmapData, а альфа-компонент - четвертый байт, bitmapData [3]. –

Смежные вопросы