UIView. Почему субподъемы вне его родительского объема не получают прикосновения?
У меня есть простая тривиальная иерархия родительских/дочерних элементов UIView. Один родитель (UIView). Один ребенок (UIButton). Ограничения родителей меньше, чем ограничение на ребенка, так что часть ребенка выходит за пределы ограничивающей рамки его родителя.
Здесь проблема: те части дочернего элемента вне bbox родителя не получают штрихи. Только нажатие внутри bbox родителя позволяет дочерней кнопке получать штрихи.
Кто-нибудь может предложить исправление/обход?
UPDATE
Для тех, кто следит за этим вопросом, вот решение, которое я реализовал в результате @Bastians самый отличный ответ:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL isInside = [super pointInside:point withEvent:event];
// identify the button view subclass
UIButton *b = (UIButton *)[self viewWithTag:3232];
CGPoint inButtonSpace = [self convertPoint:point toView:b];
BOOL isInsideButton = [b pointInside:inButtonSpace withEvent:nil];
if (isInsideButton) {
return isInsideButton;
} // if (YES == isInsideButton)
return isInside;
}
Ответы
Ответ 1
Проблема - цепочка респондентов. Когда вы прикасаетесь к экрану, он будет спускаться от родителей к ребенку.
Итак, когда вы касаетесь экрана, родитель увидит, что прикосновение находится за пределами его собственных границ, и поэтому дети даже не спросят.
Функция, которая делает это hitTest. Если у вас есть собственный класс UIView, вы можете перезаписать его и вернуть кнопку самостоятельно.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
Ответ 2
Per Явная документация, самый простой и надежный способ, которым я нашел это, - переопределить hitTest:withEvent:
в суперклассе вашего обрезанный вид выглядит следующим образом:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// Convert the point to the target view coordinate system.
// The target view isn't necessarily the immediate subview
CGPoint pointForTargetView = [self.targetView convertPoint:point fromView:self];
if (CGRectContainsPoint(self.targetView.bounds, pointForTargetView)) {
// The target view may have its view hierarchy,
// so call its hitTest method to return the right hit-test view
return [self.targetView hitTest:pointForTargetView withEvent:event];
}
return [super hitTest:point withEvent:event];
}
Ответ 3
Предварительное условие:
У вас есть UIButton
(названный как button1) внутри UIView
(именованный как контейнер), а кнопка1 частично находится за пределами границ контейнера.
Проблема
часть за пределами контейнера кнопки 1 не будет отклика клика.
Решение
подкласс вашего контейнера из UIView:
class Container: UIView {
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
let closeButton = viewWithTag(10086) as! UIButton //<-- note the tag value
if closeButton.pointInside(convertPoint(point, toView: closeButton), withEvent: event) {
return true
}
return super.pointInside(point, withEvent: event)
}
}
Не забудьте указать свой тэг button1 10086
Ответ 4
У меня была такая же проблема. Вам нужно только переопределить:
- (BOOL) pointInside: (CGPoint) point withEvent: (UIEvent *) событие
Вот рабочий код для пользовательского подкласса UIView, созданного исключительно для того, чтобы его можно было отключить для своих детей вне границ.
@implementation ARQViewToRightmost
// We should not need to override this one !!!
/*-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if ([self isInside:point])
return self;
return nil;
}*/
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if ([self isInside:point])
return YES; // That answer will make hitTest continue recursively probing the view subviews for hit
return NO;
}
// Check to see if the point is within the bounds of the view. We've extended the bounds to the max right
// Make sure you do not have any other sibling UIViews to the right of this one as they will never receive events
- (BOOL) isInside:(CGPoint)point
{
CGFloat maxWidth = CGFLOAT_MAX;
CGRect rect = CGRectMake(0, 0, maxWidth, self.frame.size.height);
if (CGRectContainsPoint(rect, point))
return YES;
return NO;
}
@end