1. ホーム
  2. objective-c

[解決済み] hitTest:withEventを使用して、スーパービューのフレーム外にあるサブビューのタッチをキャプチャする。

2023-01-10 04:08:36

質問

私の問題です。 私はスーパービュー EditView があり、それは基本的にアプリケーションのフレーム全体を占め、そしてサブビュー MenuView があり、下の 20% だけを占有し、さらに MenuView にはそれ自身のサブビューである ButtonView の外側に存在します。 MenuView の境界の外に存在するもの(このようなもの。 ButtonView.frame.origin.y = -100 ).

(注 EditView の一部でない他のサブビューがあります。 MenuView のビュー階層には含まれませんが、答えに影響を与えるかもしれません)。

おそらく、この問題はすでにご存知でしょう。 ButtonView の境界内にある場合 MenuView (の範囲内にあるとき(より具体的には、私のタッチが MenuView の範囲内にあるとき)。 ButtonView はタッチイベントに反応する。タッチが MenuView の境界の外(しかしまだ ButtonView の境界内) では、タッチイベントを受信しません。 ButtonView .

  • (E)は EditView であり、すべてのビューの親である
  • (M) は MenuView であり、EditViewのサブビューである
  • (B)は ButtonView であり、MenuViewのサブビューである

ダイアグラムです。

+------------------------------+
|E                             |
|                              |
|                              |
|                              |
|                              |
|+-----+                       |
||B    |                       |
|+-----+                       |
|+----------------------------+|
||M                           ||
||                            ||
|+----------------------------+|
+------------------------------+

(B)は(M)のフレームの外にあるため、(B)の領域でのタップは(M)に送られることはありません。実際、この場合(M)はタッチを分析することはなく、タッチは階層内の次のオブジェクトに送られます。

ゴールです。 私は hitTest:withEvent: をオーバーライドすることで、この問題を解決できることはわかりますが、その方法を正確に理解していません。私の場合 hitTest:withEvent: で上書きする必要があります。 EditView (私の'マスター'スーパービュー)でオーバーライドされますか?それとも MenuView でオーバーライドする必要がありますか?それとも、私はこのことについて間違って考えているのでしょうか?

もしこれが長い説明を必要とするなら、良いオンライン リソースが役に立つでしょう - Apple の UIView ドキュメントを除いて。

ありがとうございます!

どのように解決するのですか?

それは、ビューがその境界にサブビューをクリップするケースを処理し、隠されている可能性があり、さらに重要なことは、サブビューが複雑なビュー階層である場合、正しいサブビューが返されることです。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    if (self.clipsToBounds) {
        return nil;
    }

    if (self.hidden) {
        return nil;
    }

    if (self.alpha == 0) {
        return nil;
    }

    for (UIView *subview in self.subviews.reverseObjectEnumerator) {
        CGPoint subPoint = [subview convertPoint:point fromView:self];
        UIView *result = [subview hitTest:subPoint withEvent:event];

        if (result) {
            return result;
        }
    }

    return nil;
}

SWIFT 3

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    if clipsToBounds || isHidden || alpha == 0 {
        return nil
    }

    for subview in subviews.reversed() {
        let subPoint = subview.convert(point, from: self)
        if let result = subview.hitTest(subPoint, with: event) {
            return result
        }
    }

    return nil
}

このソリューションをより複雑なユースケースに使おうとしている人の助けになれば幸いです。