web-dev-qa-db-ja.com

UIScrollViewからタッチを盗む方法は?

今日は創造的な時間で、UIScrollViewからタッチを盗み、それらを特定のサブビューに即座に送信し、残りのスクロールビューのデフォルトの動作を維持する方法について、かなり包括的な調査を行いました。 UITableView内にUIPickerViewを含めることを検討してください。デフォルトの動作では、ピッカービュー上で指をドラッグすると、スクロールビューがスクロールされ、ピッカービューは変更されません。

私が試した最初のことはオーバーライドすることでした

- (BOOL)touchesShouldCancelInContentView:(UIView *)view

そして、UIScrollViewがピッカービュー内のタッチをキャンセルできないようにします。これは機能しますが、不快な副作用があります。ピッカービューがすぐに応答するようにするため、delaysContentTouchesをNOに設定する必要があります。問題は、テーブルビューの残りのセルがすぐに応答しないようにすることです。応答すると、テーブルビューのセルが常にスクロールを開始する前に数ミリ秒間強調表示されます。

私が試した2番目のことはオーバーライドすることでした

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

私が読んだのは、スクロールビューは常にそれ自体を返すため、サブビューからタッチを「盗み取り」、スクロールビューに関係のないものは後でサブビューに送信するためです。ただし、これはもう当てはまりません。 UIScrollViewのデフォルトのhitTest:withEvent:の実装は、実際にはタッチを受けるサブビューを返します。代わりに、ジェスチャー認識機能を使用してタッチをインターセプトします。

したがって、私が試みた3番目のことは、独自のジェスチャー認識機能を実装し、タッチがピッカービューの外にある場合は失敗させ、それ以外の場合は成功させることでした。次に、次のコードを使用してジェスチャ認識機能が失敗しない限り、スクロールビューのすべてのジェスチャ認識機能が失敗するように設定します。

for (UIGestureRecognizer * gestureRecognizer in self.tableView.gestureRecognizers)
{
    [gestureRecognizer requireGestureRecognizerToFail:myRecognizer];
}

これは実際にはスクロールビューからタッチを盗みますが、ピッカービューはそれらを受け取りません。ですから、ジェスチャーレコグナイザーが受け取るすべてのタッチをこのコードを使用して送信することもできます。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch *touch in touches)
        [touch.view touchesBegan:touches withEvent:event];
}

上記のコードは簡略化されたバージョンです。また、ビューがピッカービュー(またはそのサブビューの1つ)であることを確認し、前述のようにジェスチャー認識機能に適切な状態を設定します。キャンセル、終了、引っ越しについても同じことをしました。ただし、ピッカービューはまだ応答していませんでした。

また、通常の作業に戻る前に、最後に1つ試してみました。広範囲にわたるグーグルで、ネストされたUIScrollViewsが3.x以降魔法のように機能することを読んだので、ピッカービューをネストされたUIScrollView内に配置し、次のプロパティを設定しました。

scrollView.delaysContentTouches = NO;
scrollView.canCancelContentTouches = NO;

予想通り、外側のスクロールビューは内側のスクロールビューをピッカービューと同じように処理しなかったため、内側のスクロールビューはタッチを受けませんでした。ロングショットだと思ったのですが、実装が簡単なので、試してみる価値はあると思いました。

私が知っているのは、UIScrollViewにUIScrollViewDelayedTouchesBeganGestureRecognizerというジェスチャー認識機能があり、150(?)ミリ秒後にタッチをインターセプトして適切なサブビューに送信することです。私は、スクロールビューのデフォルトの認識機能を失敗させ、タッチを遅らせる代わりに、すぐにそれらをピッカービューに送信する、同様の認識機能を記述できるはずだと考えています。したがって、そのような認識エンジンの記述方法を知っている人がいれば、私に知らせてください。問題に対する他の解決策があれば、それも大歓迎です。

質問全体を読んでいただきありがとうございます。回答がわからない場合でも、質問に賛成票を投じて注目を集めることができます(できれば回答できる人から)。ありがとう! :)

38
Erik B

答えを見つける前に質問をしなければならない場合があります。ダンレイにも同様の問題があり、非常に異なるソリューションでそれを解決しました。

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView* result = [super hitTest:point withEvent:event];

    if ([result.superview isKindOfClass:[UIPickerView class]])
    {
        self.scrollEnabled = NO;
    }
    else 
    {
        self.scrollEnabled = YES;    
    }
    return result;
}

私はコードをテストしましたが、それも私にとってはうまくいきます。ただし、これはスクロールビューからタッチを実際に盗むわけではないため、実際にタッチを盗む方法を誰かが知っているとしたら、すばらしいでしょう。

ソース: ITableView.tableFooterView内のUIPickerViewはドラッグタッチを受け取らない

35
Erik B

少し遅れましたが、私はこの解決策を見つけました: http://www.cocoanetics.com/2010/06/hacking-uiscrollview-gesture-recognizers/ 私にとってはうまくいきます

4

私もパーティーに遅刻しましたが、初心者の場合、スクロールビューでスワイプを無視するのをフラットにするだけの場合は、パンジェスチャーレコグナイザーをスワイプを無視するビューに追加することでうまくいきました。この:

let panGesture = UIPanGestureRecognizer()
panGesture.cancelsTouchesInView = false
myView?.addGestureRecognizer(panGesture)
1
Brian Sachetta