Не удается получить UIMenuController для отображения пользовательских элементов

Итак, я не уверен, что делаю что-то не так, но у меня есть UIViewController, на котором есть UICollectionView. В UIViewController's viewDidLoad метод, я делаю следующее, он не добавляет какие-либо пользовательские пункты меню во всплывающее окно, которое появляется.

UIMenuItem *removeItem = [[UIMenuItem alloc] initWithTitle:@"Remove" action:@selector(handleRemoveItem:)];
UIMenuItem *duplicateItem = [[UIMenuItem alloc] initWithTitle:@"Duplicate" action:@selector(handleDuplicateItem:)];

[[UIMenuController sharedMenuController] setMenuItems:@[removeItem, duplicateItem]];

[removeItem release];
[duplicateItem release];

Я установил collectionView:shouldShowMenuForItemAtIndexPath: и collectionView:canPerformAction:forItemAtIndexPath:withSender: возвращать YES при любых обстоятельствах, но не смотря ни на что, будут отображаться только "Вырезать", "Копировать" и "Вставить".

Разве я не реализовал это полностью, или я не сделал это правильно?

PS - Я просмотрел как можно больше примеров в Google и не нашел ничего, что могло бы помочь.

3 ответа

Решение

Ты прав. Невозможно настроить меню, которое появляется при длительном нажатии на ячейку табличного представления или ячейку представления коллекции.

Я обсуждаю проблему в моей книге:

http://www.apeth.com/iOSBook/ch21.html

Как я уже сказал, Копировать, Вырезать и Вставить - это единственный выбор, который вы можете иметь. Вам нужно будет заставить меню исходить из чего-то другого, если вы хотите настроить его.

РЕДАКТИРОВАТЬ: В версии моей книги для iOS 7, я демонстрирую способ сделать это. То же самое касается ячеек табличного представления и ячеек коллекционного представления, поэтому я начну с решения для ячеек табличного представления. Хитрость заключается в том, что вы должны реализовать метод действия в подклассе ячейки. Например, если ваш селектор пользовательских действий abbrev:, вы должны создать подкласс ячейки и реализовать abbrev::

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p454tableCellMenus2/ch21p718sections/MyCell.m

Это единственная сложная часть. Затем, вернувшись в свой класс контроллера, вы делаете для abbrev: именно то, что вы сделали бы для любого меню. В shouldShowMenuForRowAtIndexPath:добавьте его в пользовательское меню. Затем реализовать canPerformAction: а также performAction: как и следовало ожидать (прокрутите до конца):

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p454tableCellMenus2/ch21p718sections/RootViewController.m

Вот параллельная реализация для ячеек представления коллекции: подкласс ячейки:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p466collectionViewFlowLayout2/ch21p748collectionViewFlowLayout2/Cell.m

И контроллер (прокрутите до конца):

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch08p466collectionViewFlowLayout2/ch21p748collectionViewFlowLayout2/ViewController.m

Эти подходы также переведены на Swift (не без каких-либо трудностей) в издании iOS 8 моей книги.

Мне удалось реализовать пользовательские меню на UICollectionViewCell, следуя инструкциям по этой ссылке ( /questions/33148644/kopirovat-vyinosku-v-uicollectionview/33148646#33148646) с некоторой импровизацией.

В моем UICollectionViewController я реализовал пользовательские пункты меню, добавив их в контроллер меню, как в ссылке.

Затем я реализовал следующее в UICollectionViewController:

- (BOOL)collectionView:(UICollectionView *)cv canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
return NO;
}

- (BOOL)collectionView:(UICollectionView *)cv shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}

- (void)collectionView:(UICollectionView *)cv performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {

NSLog(@"perform action:%@", NSStringFromSelector(action));
}

В моем UICollectionViewCell я реализовал примерно следующее:

- (BOOL)canBecomeFirstResponder {
return YES;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {

if (action == @selector(onCustom1:)) {
    return YES;
}

if (action == @selector(onCustom2:)) {
    return YES;
} 
return NO;
}

Эти действия должны быть такими же, как реализованные в контроллере коллекции.

Если кто-то хочет включить функции копирования или вставки, добавьте их в canPerformAction: и затем измените collectionView::canPerformAction: для возврата YES.

Возможно, это не лучший способ сделать это, но сработало для меня.

Шаг 1. Создание пунктов меню

UIMenuItem* miCustom1 = [[UIMenuItem alloc] initWithTitle:@"Custom 1" action:@selector(onCustom1:)];
UIMenuItem* miCustom2 = [[UIMenuItem alloc] initWithTitle: @"Custom 2" action:@selector(onCustom2:)];

Шаг 2: Создать MenuController

UIMenuController* mc = [UIMenuController sharedMenuController];

Шаг 3: Добавить элементы в контроллер меню

mc.menuItems = [NSArray arrayWithObjects: miCustom1, miCustom2, nil];

Шаг 4. Создание методов действий для элементов

- (void) onCustom1: (UIMenuController*) sender
{
}

- (void) onCustom2: (UIMenuController*) sender
{
}

Шаг 5: опционально установить FirstResponder для действий

- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
    if ( action == @selector( onCustom1: ) )
    {
        return YES; // logic here for context menu show/hide
    }

    if ( action == @selector( onCustom2: ) )
    {
        return NO;  // logic here for context menu show/hide
    }

    if ( action == @selector( copy: ) )
    {
        // turn off copy: if you like:
        return NO;
    }

    return [super canPerformAction: action withSender: sender];
}

Шаг 6: Наконец покажите свой MenuController на некоторых кнопках

UIMenuController* mc = [UIMenuController sharedMenuController];

CGRect bounds = sender.view.bounds;

[mc setTargetRect: sender.view.frame inView:sender.view.superview];
[mc setMenuVisible:YES animated: YES];
Другие вопросы по тегам