単純な-些細な-UIViewの親/子階層があります。 1つの親(UIView)。 1つの子(UIButton)。親の境界は子の境界よりも小さいため、子の一部は親の境界ボックスを超えて拡張されます。
問題は次のとおりです。親のbboxの外側にある子の部分は、タッチを受け取りますnot。親のbbox内をタップするだけで、子ボタンがタッチを受け取ることができます。
誰かが修正/回避策を提案できますか?
この質問に続く人のために、@ 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;
}
問題はレスポンダーチェーンです。ディスプレイをタッチすると、親から子へと下がります。
したがって、..画面をタッチすると、親はタッチがそれ自体の範囲外であることがわかり、子供たちも尋ねることはありません。
それを行う関数がhitTestです。独自のUIViewクラスがある場合は、それを上書きして、自分でボタンを返すことができます。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
Apple独自のドキュメント によると、これを行うために私が見つけた最も簡単で信頼性の高い方法は、クリップされたビューのスーパークラスのhitTest:withEvent:
を次のようにオーバーライドすることです。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// Convert the point to the target view's 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];
}
- @dugla、質問ありがとうございます!
- @Bastianと@laoyur、回答ありがとうございます!
Swift 4
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if yourChildView.point(inside: convert(point, to: yourChildView), with: event) {
return true
}
return super.point(inside: point, with: event)
}
前提条件:
UIButton
(コンテナと名付けられた)の中にUIView
(button1と名付けられた)があり、button1は部分的にコンテナの境界の外にあります。
問題:
button1のコンテナの外側の部分は、クリックに応答しません。
解決策:
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
のタグを付けることを忘れないでください