web-dev-qa-db-ja.com

iOS-ビューを介してすべてのタッチを転送します

他の多くのビューの上にビューがオーバーレイされています。私は画面上のいくつかのタッチを検出するためだけに使用していますが、それ以外は、スクロールビューなどの下にある他のビューの動作をビューで停止させたくないです。すべてのタッチをどのように転送できますかこのオーバーレイビュー? UIViewのサブカルです。

124
sol

オーバーレイビューからその下のビューにタッチを渡すには、UIViewで次のメソッドを実装します。

Objective-C:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Passing all touches to the next view (if any), in the view stack.");
    return NO;
}

迅速:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    print("Passing all touches to the next view (if any), in the view stack.")
    return false
}
104
PixelCloudSt
myWebView.userInteractionEnabled = NO;

必要なのはこれだけでした!

99
rmp251

これは古いスレッドですが、検索で出てきたので、2cを追加すると思いました。サブビューでカバーするUIViewがあり、サブビューの1つにヒットするタッチのみをインターセプトするため、PixelCloudStの答えを修正しました

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView* subview in self.subviews ) {
        if ( [subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil ) {
            return YES;
        }
    }
    return NO;
}
51
fresidue

@fresidue answerの改善されたバージョン。このUIViewサブクラスは、サブビューの外側にタッチを渡す透明なビューとして使用できます。 Objective-Cでの実装:

@interface PassthroughView : UIView

@end

@implementation PassthroughView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView *view in self.subviews) {
        if (!view.hidden && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
            return YES;
        }
    }
    return NO;
}

@end

およびSwift:

class PassthroughView: UIView {
  override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    return subviews.contains(where: {
      !$0.isHidden && $0.point(inside: self.convert(point, to: $0), with: event)
    })
  }
}
32

タッチを転送したいビューがサブビュー/スーパービューではない場合、UIViewサブクラスでカスタムプロパティを次のように設定できます。

@interface SomeViewSubclass : UIView {

    id forwardableTouchee;

}
@property (retain) id forwardableTouchee;

.mで必ず合成してください:

@synthesize forwardableTouchee;

そして、次のようなUIResponderメソッドのいずれかに以下を含めます。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [self.forwardableTouchee touchesBegan:touches withEvent:event];

}

UIViewのインスタンスを作成する場所に関係なく、forwardableToucheeプロパティを、イベントの転送先のビューに設定します。

    SomeViewSubclass *view = [[[SomeViewSubclass alloc] initWithFrame:someRect] autorelease];
    view.forwardableTouchee = someOtherView;
6
Chris Ladd

UIStackViewでも同様の問題がありました(他のビューでもかまいません)。私の構成は次のとおりでした: View controller with containerView and StackView

これは、ボタンを横に置いて、背景に配置する必要があるコンテナがある古典的なケースです。レイアウトの目的のために、UIStackViewにボタンを含めましたが、stackViewの中央の(空の)部分がタッチをインターセプトします:-(

私がやったのは、タッチ可能なサブビューを定義するプロパティを持つUIStackViewのサブクラスを作成することです。サイドボタン(* viewsWithActiveTouch *配列に含まれる)へのタッチはボタンに与えられますが、スタックビューに対するこれらのビュー以外のタッチはインターセプトされないため、スタックの下にあるものに渡されます見る。

/** Subclass of UIStackView that does not accept touches, except for specific subviews given in the viewsWithActiveTouch array */
class NoTouchStackView: UIStackView {

  var viewsWithActiveTouch: [UIView]?

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

    if let activeViews = viewsWithActiveTouch {
        for view in activeViews {
           if CGRectContainsPoint(view.frame, point) {
                return view

           }
        }
     }
     return nil
   }
}
5
Frédéric Adda

In Swift 5

class ThroughView: UIView {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        guard let slideView = subviews.first else {
            return false
        }

        return slideView.hitTest(convert(point, to: slideView), with: event) != nil
    }
}
2
onmyway133

このようなものを試してみてください...

for (UIView *view in subviews)
  [view touchesBegan:touches withEvent:event];

たとえば、上記のコードのtouchesBeganメソッドでは、ビューのすべてのサブビューにタッチを渡します。

0
Jordan