1

長押しジェスチャ認識機能を含むビューがあります。

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {            
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDetected:)];
        [self addGestureRecognizer:longPress];
        [longPress release];
    }
    return self;
}

長押しが検出されたら、ビューの上に単一のアクションを含む UIMenuViewController を表示し、そのメニュー項目がタップされたときにブロックを実行したい:

- (void)longPressDetected:(UILongPressGestureRecognizer *)recognizer {
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        [self becomeFirstResponder];
        UIMenuController *menuController = [UIMenuController sharedMenuController];
        UIMenuItem *actionItem = [[UIMenuItem alloc] initWithTitle:@"Action" action:@selector(someActionSelector)];
        [menuController setMenuItems:[NSArray arrayWithObject:actionItem]];
        [actionItem release];

        [menuController setTargetRect:self.frame inView:self.superview];
        [menuController setMenuVisible:YES animated:YES];
    }
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(copy:) || action == @selector(cut:) || action == @selector(delete:) || 
        action == @selector(paste:) || action == @selector(select:) || action == @selector(selectAll:)) {
        return NO;
    }
    else if (action == @selector(someActionSelector)) {
        return YES;
    }
    else {
        return [super canPerformAction:action withSender:sender];
    }
}

- (void)someActionSelector {
    if (self.actionBlock) {
        self.actionBlock();
    }
}

問題は、これが 2 回目の長押しとタップの組み合わせの後にのみ機能することです。ビューを初めて長押しすると、メニューが表示されますが、メニューをタップしても何も起こりません。もう一度メニューを表示してタップすると、ブロックが実行されます。

デバッガーはsomeActionSelector、2 回目のタップでのみブレークポイントに到達することを示しています。これはなぜですか?

4

1 に答える 1

0

私はそれを考え出した。長押しをリッスンするビューは、フレームが変更されたときにいくつかのサブビューを再配置するビュー内に含まれています (オーバーライドすることによりsetFrame:、これは悪い考えのように思えますが、別の方法は考えられませんでした)。したがって、長押しが発生すると、リスニング ビューの親の親で がトリガーlayoutSubviewsされ、リスニング ビューの親のフレームが設定され、リスニング ビューが再配置され、レスポンダー チェーンが切断されるか、メニューが非アクティブ化されるように見えます。 . 解決策は、オーバーライド内に条件を追加してsetFrame:、フレームが実際に変更された場合にのみレイアウトをトリガーすることでした。これは長押しではありません。この問題を完全に回避するフレームの変更を聞くためのより良い代替手段があると確信しています.コメントでそれらを提案してください.

于 2012-03-14T19:47:44.957 に答える