ここでまだ答えを探している人はコードです(主なアイデアはneon1に属します。リンクされた質問を参照してください)。
アイデアは次のとおりです。レスポンダーが特定のアクションを処理する方法を知らない場合、チェーン内の次のレスポンダーに伝播します。これまでのところ、ファーストレスポンダーの候補は 2 つあります。
- 細胞
- テキストフィールド
それぞれがレスポンダーのチェーンを別々に持っています (実際、いいえ、共通の祖先を持っているため、チェーンには共通点がありますが、それを使用することはできません):
UITextField <- UIView <- ... <- UIWindow <- UIApplication
UITableViewCell <- UIView <- ... <- UIWindow <- UIApplication
したがって、次の一連のレスポンダーが必要です。
UITextField <- UITableViewCell <- ..... <- UIWindow <- UIApplication
UITextField をサブクラス化する必要があります (コードはhereから取得されます)。
CustomResponderTextView.h
@interface CustomResponderTextView : UITextView
@property (nonatomic, weak) UIResponder *overrideNextResponder;
@end
CustomResponderTextView.m
@implementation CustomResponderTextView
@synthesize overrideNextResponder;
- (UIResponder *)nextResponder {
if (overrideNextResponder != nil)
return overrideNextResponder;
else
return [super nextResponder];
}
@end
このコードは非常に単純です。カスタムの次のレスポンダーを設定していない場合は実際のレスポンダーを返し、それ以外の場合はカスタムのレスポンダーを返します。
これで、コードに新しいレスポンダーを設定できます (私の例ではカスタム アクションを追加しています):
CustomCell.m
@implementation CustomCell
- (BOOL) canBecomeFirstResponder {
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
return (action == @selector(copyMessage:) || action == @selector(deleteMessage:));
}
@end
- (void) copyMessage:(id)sender {
// copy logic here
}
- (void) deleteMessage:(id)sender {
// delete logic here
}
コントローラ
- (void) viewDidLoad {
...
UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"Custom copy" action:@selector(copyMessage:)];
UIMenuItem *deleteItem = [[UIMenuItem alloc] initWithTitle:@"Custom delete" action:@selector(deleteMessage:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:@[copyItem, deleteItem]];
...
}
- (void) longCellTap {
// cell is UITableViewCell, that has received tap
if ([self.textField isFirstResponder]) {
self.messageTextView.overrideNextResponder = cell;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuDidHide:) name:UIMenuControllerDidHideMenuNotification object:nil];
} else {
[cell becomeFirstResponder];
}
}
- (void)menuDidHide:(NSNotification*)notification {
self.messageTextView.overrideNextResponder = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidHideMenuNotification object:nil];
}
最後のステップは、最初のレスポンダー (この場合はテキスト フィールド) をプロポさせ、次のレスポンダー (この場合はセル) にアクションを実行させることですcopyMessage:。私たちが知っているように、特定のレスポンダーがアクションを処理できる場合、deleteMessage:iOs が知っているように送信します。canPerformAction:withSender:
CustomResponderTextView.m次の関数を変更して追加する必要があります。
CustomResponderTextView.m
...
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (overrideNextResponder != nil)
return NO;
else
return [super canPerformAction:action withSender:sender];
}
...
カスタムのネクスト レスポンダーを設定した場合は、それにすべてのアクションを送信します (textField で何らかのアクションが必要な場合は、この部分を変更できます)。