いくつかの「サブビュー」を含むUIView(「コンテナービュー」)があります。 UITapGestureRecognizerをコンテナービューに追加し、コンテナービューの内側でサブビューの外側の領域に触れるとアクティブになるようにします。
現時点では、サブビュー内を含むコンテナービュー内の任意の場所をタッチすると、ジェスチャー認識機能がアクティブになります。
実装は次のようになります。コントローラで:
ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array];
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)];
[containerView addGestureRecognizer:tap];
[self.view addSubView:containerView];
ContainerView.m
-(id)initWithSubviews:(NSArray *)array {
for (subView *s in array) {
[self addSubView:s];
}
return self;
}
問題は、サブビューの後にジェスチャー認識機能が追加されるために発生すると思います。それが真の場合、ソリューションはinitWithSubViewsメソッドを2つの別々のメソッドに分割する必要がありますが、これは避けたいと思います。
ありがとうございました
iOS 6では、この正確な問題を解決する優れた新機能が導入されています。UIView(サブビュー)はgestureRecognizerShouldBegin:
(スーパービューに接続されたジェスチャー認識機能)からNOを返すことができます。実際、これは、一部のジェスチャ認識機能に関するUIViewサブクラスのデフォルトです(たとえば、スーパービューにアタッチされたUITapGestureRecognizerに関するUIButton)。
このトピックに関する私の本を参照してください: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers
以下の簡単な方法を使用しました。 完全に機能します!
UIGestureRecognizerDelegate関数を実装し、スーパービューでのタッチのみを受け入れ、サブビューでのタッチを受け入れない:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews
return NO;
}
return YES;
}
次のようにして、なんとか動作させることができました。
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)];
// ...
-(void) tapGestureHandler:(UITapGestureRecognizer *)sender {
CGPoint point = [sender locationInView:sender.view];
UIView *viewTouched = [sender.view hitTest:point withEvent:nil];
if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) {
// Do nothing;
} else {
// respond to touch action
}
}
デリゲートメソッドを追加および設定することを忘れないでください-
UIViewControllerの.hファイルにこのデリゲートを含めます
@interface YourViewController: UIViewController<UIGestureRecogniserDelegate>
次に、tapGestureオブジェクトを作成する場所(たとえば、viewDidLoad内)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(actionMethodYouWantToHappenOnTap)];
tap.delegate = self; //Remember to set delegate! Otherwise the delegate method won't get called.
[self.view addGestureRecognizer:tap];
デリゲートメソッドを設定することを忘れないtap.delegate = self;
すると、タップのデリゲートメソッドがタップで発生します。
このメソッド内では、タップジェスチャー認識を使用したい場合に処理します。私のコードでは、特定のサブビューが表示されている場合にタップを無視するようにしました。
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (!mySubview.hidden){
return NO; //This fired if said subview was visible, though whatever the condition of where and when you want tap to work, can be handled within this delegate method.
}
return YES;
}
これが同じ問題を抱えている他の人に役立つことを願っています。私が見つけたデリゲートメソッドを設定することを思い出すことは、簡単に見落とされるものでした。
乾杯
答えがたくさんあり、別の代替ソリューションを追加しています。タッチを受け取りたくないサブビューのビュータグを1として初期化し、以下を実行します。
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tap.delegate = self;
[self.view addGestureRecognizer:tap];
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view.tag == 1) {
return NO;
}
return YES;
}
-(void)handleTap:(id)sender
{
//Handle tap...
}
このように、タッチジェスチャは、必要なビューからのみ受信されます。
ContainerViewにUITapGestureRecognizer
を追加すると、ContainerView全体で応答するはずです。サブビューは気にしません。
ジェスチャーの場所を確認し、サブビューの位置にある場合は、ジェスチャーアクションをスキップしてください。
- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer {
CGPoint tapPoint = [gestureRecognizer locationInView:nil];
//check your tapPoint contains ur subview frame, skip.else do ur actions
}
追加:
私はもっと良いものを考えました。
あなたのハンドラで
-(void)tapGestureHandler:(UITapGestureHandler)gesture
gesture.Viewがスーパービューかどうかを確認します。サブビューがタップされると、サブビューを返します。
================================================== ==
スーパービュー内でオーバーライドすることをお勧めします。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
これは、ジェスチャーがビュー内にあるかどうかを判断するために呼び出されます
この質問に対する回答を参照して、デフォルトでどのように動作するかを確認してください。
iOSのイベント処理-hitTest:withEvent:とpointInside:withEvent:はどのように関連していますか?
ポイントがサブビューのいずれかにあるかどうかを確認できます。はいの場合はnilを返し、そうでない場合はselfを返します。
OR
各サブビューに、何もしないタプスチャー認識機能を追加します。サブビューのジェスチャー認識機能は、デフォルトでスーパービューのジェスチャー認識機能をキャンセルします。サブビュー数が多い場合は、メモリフットプリントに注目します。
Swift 4の回答を更新
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view != yourView
{
return false
}
return true
}
その前に、オブジェクトにデリゲートプロパティを設定していることを確認してください。