web-dev-qa-db-ja.com

UIScrollViewは、ビューコントローラでtouchesBegan、touchesMoved、touchsEndedを防止します

ビューコントローラー(UIViewControllerのカスタムサブクラス)でいくつかのUIコンポーネントのタッチを処理しています。メソッドtouchesBegan:withEvent:touchesMoved:withEvent:、およびtouchesEnded:withEvent:があります。正常に動作していました。次に、階層の最上位ビューとしてスクロールビュー(UIScrollView)を追加しました。

これで、ViewControllerのタッチハンドラーが機能しなくなりました。彼らは呼ばれません。興味深いのは、スクロールビュー内に機能する他のさまざまなUIコンポーネントがあることです。ボタンもあれば、独自のtouchesBegan:withEvent:を定義するカスタムビューなどもあります。機能しないのは、ViewControllerのタッチハンドラーだけです。

スクロールビューがそれ自体の目的でこれらのタッチをインターセプトしているためかもしれないと思いましたが、UIScrollViewをサブクラス化し、それが機能するかどうかを確認するために、常にtouchesShouldBegin:withEvent:inContentView:からYESを返し、常にtouchesShouldCancelInContentView:からNOを返します。それでも動作しません。

それが違いを生むなら、私のビューコントローラーはタブバーコントローラー内にありますが、それは関係ないと思います。

誰かがこの問題を抱えていて、すぐに解決できる人はいますか?私の推測では、レスポンダーチェーンの上のスクロールビューモンキーです。猿に戻せますか?他に何もわからない場合は、スクロールビューの下のトップレベルビューをカスタムビューにして、メッセージをView Controllerに転送しますが、見苦しいようです。

26
morningstar

uIScrollViewクラスのサブクラスを作成し、touchesBegan:およびその他のtouchメソッドを次のようにオーバーライドします。

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

// If not dragging, send event to next responder
  if (!self.dragging){ 
    [self.nextResponder touchesBegan: touches withEvent:event]; 
  }
  else{
    [super touchesBegan: touches withEvent: event];
  }
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

// If not dragging, send event to next responder
    if (!self.dragging){ 
     [self.nextResponder touchesMoved: touches withEvent:event]; 
   }
   else{
     [super touchesMoved: touches withEvent: event];
   }
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

  // If not dragging, send event to next responder
   if (!self.dragging){ 
     [self.nextResponder touchesEnded: touches withEvent:event]; 
   }
   else{
     [super touchesEnded: touches withEvent: event];
   }
}
22
user1085093

これはうまくいきましたが、nextResponderはサブクラスでオーバーライドするように「推奨」されているUIViewメソッドの1つではないため、「それを回避」できるかどうかはわかりません。

@interface ResponderRedirectingView : UIView {

    IBOutlet UIResponder *newNextResponder;

}

@property (nonatomic, assign) IBOutlet UIResponder *newNextResponder;

@end


@implementation ResponderRedirectingView

@synthesize newNextResponder;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (UIResponder *)nextResponder {
    return self.newNextResponder;
}

- (void)dealloc
{
    [super dealloc];
}

@end

次に、Interface Builderで、スクロールビューの直接サブビューをこれらの1つにし、そのnewNextResponderを接続して、スクロールビューをスキップし、ViewControllerを直接ポイントしました。

これも機能し、nextResponderのオーバーライドを次のオーバーライドに置き換えます。

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesBegan:touches withEvent:event];
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesMoved:touches withEvent:event];
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.newNextResponder touchesCancelled:touches withEvent:event];
}
2
morningstar

「正常に機能していました。次に、階層の最上位ビューとしてスクロールビュー(UIScrollView)を追加しました。」

アイテムを含むコンテンツビューの上にスクロールビューがありますか?

すべてのコンポーネントは、スクロールビューの背後にあるビューではなく、スクロールビューにある必要があります

0
henghonglee

user1085093の答えは私のために働いた。ただし、タッチを少し以上動かすと、パンジェスチャとして解釈されます。

Pan Gestureレコグナイザーの動作を変更して、2本の指が必要になるようにすることで、これを克服しました。

-(void)awakeFromNib
{
    NSArray                 *gestureRecognizers = self.gestureRecognizers;
    UIGestureRecognizer     *gestureRecognizer;

    for (gestureRecognizer in gestureRecognizers) {
        if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
            UIPanGestureRecognizer      *pgRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
            pgRecognizer.minimumNumberOfTouches = 2;
        }
    }

}
0
user2002649