私はこれがどのように行われるかを理解しようとしています正しい方法。私は状況を描写しようとしました:
UITableView
のサブビューとしてUIView
を追加しています。 UIView
はタップとpinchGestureRecognizer
に応答しますが、そうすると、tableviewはこれら2つのジェスチャに反応しなくなります(スワイプに反応します)。
次のコードで動作するようにしましたが、明らかにニースのソリューションではなく、より良い方法があると確信しています。これはUIView
(スーパービュー)に配置されます:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if([super hitTest:point withEvent:event] == self) {
for (id gesture in self.gestureRecognizers) {
[gesture setEnabled:YES];
}
return self;
}
for (id gesture in self.gestureRecognizers) {
[gesture setEnabled:NO];
}
return [self.subviews lastObject];
}
私は非常に似た問題を抱えていて、私の解決策を見つけました in SO question 。要約すると、自分をUIGestureRecognizer
のデリゲートとして設定し、許可する前にターゲットビューを確認しますタッチを処理する認識エンジン関連するデリゲートメソッドは次のとおりです。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
サブビューへのタッチイベントのブロックは、デフォルトの動作です。この動作を変更できます:
UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];
独自のテーブルビューを持つドロップダウンサブビューを表示していました。その結果、touch.view
は、UITableViewCell
のようなクラスを返すことがあります。スーパークラスをステップスルーして、サブクラスであることを確認する必要がありました。
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
UIView *view = touch.view;
while (view.class != UIView.class) {
// Check if superclass is of type dropdown
if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own
NSLog(@"Is of type dropdown; returning NO");
return NO;
} else {
view = view.superview;
}
}
return YES;
}
1つの可能性は、ジェスチャー認識機能をサブクラス化して(まだ行っていない場合)、-touchesBegan:withEvent:
除外されたサブビューで各タッチが開始されたかどうかを判断し、-ignoreTouch:forEvent:
タッチした場合。
もちろん、除外されたサブビューを追跡するためのプロパティを追加する必要があります。除外されたサブビューの配列を追加することもできます。
@Pin Shih Wangでの構築 answer 。タップジェスチャ認識機能を含むビュー上のタップ以外のすべてのタップは無視されます。すべてのタップは、tapGestureRecognizer.cancelsTouchesInView = false
を設定したように、通常どおりビュー階層に転送されます。 Swift3/4のコードは次のとおりです。
func ensureBackgroundTapDismissesKeyboard() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tapGestureRecognizer.cancelsTouchesInView = false
self.view.addGestureRecognizer(tapGestureRecognizer)
}
@objc func handleTap(recognizer: UIGestureRecognizer) {
let location = recognizer.location(in: self.view)
let hitTestView = self.view.hitTest(location, with: UIEvent())
if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) {
// I dismiss the keyboard on a tap on the scroll view
// REPLACE with own logic
self.view.endEditing(true)
}
}
クラスを継承せずに実行することもできます。
ジェスチャーのコールバックセレクターでgestureRecognizersを確認できます
view.gestureRecognizersにgestureRecognizerが含まれていない場合は、無視してください
例えば
- (void)viewDidLoad
{
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
singleTapGesture.numberOfTapsRequired = 1;
}
こちらでview.gestureRecognizersを確認してください
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
UIEvent *event = [[UIEvent alloc] init];
CGPoint location = [gestureRecognizer locationInView:self.view];
//check actually view you hit via hitTest
UIView *view = [self.view hitTest:location withEvent:event];
if ([view.gestureRecognizers containsObject:gestureRecognizer]) {
//your UIView
//do something
}
else {
//your UITableView or some thing else...
//ignore
}
}
parentViewのすべてのレコグナイザーのデリゲートを実装し、レコグナイザーの同時トリガーを担当するデリゲートにGestureRecognizerメソッドを配置します。
func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool {
if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) {
return true
} else {
return false
}
}
Uは、子をトリガーするが親のレコグナイザーはトリガーしないようにする場合、failメソッドを使用できます。
https://developer.Apple.com/reference/uikit/uigesturerecognizerdelegate
特定のビューのスーパービューにアタッチされたすべてのジェスチャレコグナイザーをブロックするために設計されたUIGestureRecognizerサブクラスを作成しました。
これは私のWEPopoverプロジェクトの一部です。あなたはそれを見つけることができます こちら 。
あなたはそれをオフにしてオンにすることができます....私のコードでは、キーボードが表示されていないときにオフにする必要があるため、このようなことをしました。あなたの状況にそれを適用することができます:
これはviewdidloadなどと呼ばれます:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
次に、2つのメソッドを作成します。
-(void) notifyShowKeyboard:(NSNotification *)inNotification
{
tap.enabled=true; // turn the gesture on
}
-(void) notifyHideKeyboard:(NSNotification *)inNotification
{
tap.enabled=false; //turn the gesture off so it wont consume the touch event
}
これにより、タップが無効になります。タップをインスタンス変数に変え、deallocで解放しなければなりませんでした。
私もポップオーバーをやっていて、これが私がやった方法です
func didTap(sender: UITapGestureRecognizer) {
let tapLocation = sender.locationInView(tableView)
if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
sender.cancelsTouchesInView = false
}
else {
delegate?.menuDimissed()
}
}