37

単純な-些細な-UIViewの親/子階層があります。1つの親(UIView)。1つの子(UIButton)。親の境界は子の境界よりも小さいため、子の一部は親の境界ボックスを超えて拡張されます。

問題は次のとおりです。親のbboxの外側にある子の部分は、タッチを受け取りませ。親の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;        
}
4

5 に答える 5

26

問題はレスポンダーチェーンです。ディスプレイをタッチすると、親から子へと下がっていきます。

したがって、..画面をタッチすると、親はタッチがそれ自体の範囲外であることがわかり、子供は尋ねることさえありません。

それを行う関数がhitTestです。独自のUIViewクラスがある場合は、それを上書きして、自分でボタンを返すことができます。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
于 2011-04-30T20:22:42.253 に答える
4

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];
}
于 2014-08-30T18:37:29.667 に答える
2

前提条件

UIButton(コンテナという名前の)の中に(button1という名前のUIView)があり、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

于 2016-12-21T06:23:39.450 に答える
2
  • @dugla、質問ありがとうございます!
  • @Bastianと@laoyur、回答ありがとうございます!

スウィフト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)
}
于 2018-02-14T22:05:47.693 に答える
-1

私は手元にまったく同じ問題を抱えていました。オーバーライドする必要があるのは次のとおりです。

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

これは、範囲外の子に対してのみタップ可能にするために作成されたカスタム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's 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
于 2013-06-04T10:51:00.167 に答える