Ответ 1
Перед началом работы вы должны знать три важные вещи:
1) Вам нужно будет написать свой пользовательский вид контроллера меню, но я думаю, вы ожидали этого. Я знаю только коммерческую реализацию настраиваемого контроллера меню, но это не должно быть слишком сложно.
2) В UIResponder
есть полезный метод, называемый -canPerformAction:withSender:
. Подробнее об этом читайте в Справочник по классу UIResponder. Вы можете использовать этот метод, чтобы определить, поддерживает ли ваше текстовое представление конкретное стандартное действие (определенное в протоколе UIResponderStandardEditActions).
Это будет полезно при выборе элементов, которые будут отображаться в вашем настраиваемом контроллере меню. Например, пункт меню "Вставить" будет отображаться только в том случае, если панель пользователя содержит строку для вставки.
3) Вы можете определить, когда будет отображаться UIMenuController
, прослушивая уведомление UIMenuControllerWillShowMenuNotification
.
Теперь, когда вы все это знаете, я начну с этого:
1) Слушайте UIMenuControllerWillShowMenuNotification
, когда текстовое представление является первым ответчиком
- (void)textViewDidBeginEditing:(UITextView *)textView {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuWillBeShown:) name:UIMenuControllerWillShowMenuNotification object:nil];
}
- (void)textViewDidEndEditing:(UITextView *)textView {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil];
}
2) Покажите свой пользовательский контроллер меню вместо стандартного UIMenuController
- (void)menuWillBeShown:(NSNotification *)notification {
CGRect menuFrame = [[UIMenuController sharedMenuController] menuFrame];
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO]; // Don't show the default menu controller
CustomMenuController *controller = ...;
controller.menuItems = ...;
// additional stuff goes here
[controller setTargetRectWithMenuFrame:menuFrame]; // menuFrame is in screen coordinates, so you might have to convert it to your menu presenting view/window/whatever
[controller setMenuVisible:YES animated:YES];
}
Разное. 1) Вы можете использовать полноэкранный UIWindow
для отображения своего пользовательского меню, чтобы он мог перекрывать строку состояния.
UIWindow *presentingWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
presentingWindow.windowLevel = UIWindowLevelStatusBar + 1;
presentingWindow.backgroundColor = [UIColor clearColor];
[presentingWindow addSubview:controller];
[presentingWindow makeKeyAndVisible];
Разное. 2). Для определения отображаемых пунктов меню вы можете использовать упомянутый -canPerformAction:withSender:
BOOL canPaste = [textView canPerformAction:@selector(paste:) withSender:nil];
BOOL canSelectAll = [textView canPerformAction:@selector(selectAll:) withSender:nil];
Разное. 3) Вам придется обрабатывать отклонение меню самостоятельно, используя UITapGestureRecognizer
в окне представления или что-то в этом роде.
Это будет нелегко, но это выполнимо, и я надеюсь, что это сработает хорошо для вас. Удачи!
Update:
Сегодня на cocoacontrols.com появилась новая реализация меню, которую вы можете захотеть проверить: https://github.com/questbeat/QBPopupMenu
Обновление 2:
Как объяснено в этом ответе, вы можете получить кадр текстового просмотра выделенного текста с помощью -caretRectForPosition:
.