Как скрыть элемент меню в пользовательском представлении?

#objective-c #cocoa #macos #nsmenuitem #nsmenu

#objective-c #cocoa #macos #nsmenuitem #nsmenu

Вопрос:

Я использую очень простое пользовательское представление (содержащее только доступное только для чтения NSTextField и NSSegmentedControl) в NSMenuItem (используя -setView: метод). Эта часть работает так, как ожидалось.

Вот проблема: в -menuNeedsUpdate: методе делегирования NSMenu я условно скрываю элемент меню. Когда я вызываю [item setHidden:YES] , элемент меню с пользовательским представлением не скрывается, но другие «ванильные» пункты меню скрываются.

Мое пользовательское представление построено в собственном XIB, и я получаю к нему доступ через пользовательский NSViewController.

Обновить

Элемент меню остается видимым, даже если я установлю флажок Скрыто в Interface Builder и удалю строку, в которой он скрыт в коде.

Обновление 2

Я также пробовал настройки hidden в пользовательском представлении до и после настройки hidden в пункте меню. Результат такой, как будто не элемент меню скрыт, а представление; элементы управления представления не видны, но там, где они должны быть, все еще есть пробел.

Обновление 3

Я изменил пример кода Apple в MenuItemView, чтобы скрыть один из элементов меню после его добавления (вставить [menuItem setHidden:YES]; в строку 87), и это имеет тот же эффект, что и в моем коде (то есть, отсутствует).

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

Обновление 4

Используя ответ Майка ниже, вот код, который я использую:

 // Declared in the header file
IBOutlet NSMenuItem *previousMenuItem;
IBOutlet NSMenuItem *togglingMenuItem; //Needs to be RETAINED

. . .

- (void)menuNeedsUpdate:(NSMenu *)menu {
    BOOL hideItem = YES; // Some criteria, obviously

    // Remove the menu item, if it was already present
    if ([menu indexOfItem:togglingMenuItem] >= 0) {
        [menu removeItem:togglingMenuItem];
    }

    // Put it back if it should be visible
    if (!onePageVisible) {
        [menu insertItem:togglingMenuItem
                 atIndex:[menu indexOfItem:previousMenuItem]   1];
    }
}
  

Ответ №1:

Вместо того, чтобы скрывать элемент, можете ли вы удалить / повторно добавить его по мере необходимости?

  [rootMenu removeItemAtIndex: 23];
  

Комментарии:

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

2. Я должен признать глубокое предубеждение в отношении: сделайте это, отправьте это, оставьте выяснение того, почему именно это сработало / не сработало, в качестве упражнения для читателя. Желаю удачи.

Ответ №2:

В методе делегирования меню menu:updateItem: atIndex: shouldCancel: я нахожу свой элемент меню пользовательского представления по тегу и устанавливаю для его вида значение nil, если он скрыт, или назначаю пользовательский вид, если он виден:

 - (BOOL)menu:(NSMenu *)menu 
    updateItem:(NSMenuItem *)item 
    atIndex:(NSInteger)index 
    shouldCancel:(BOOL)shouldCancel
{

    if ([item tag] == CUSTOM_VIEW_TAG)
    {
        [item setView:[item isHidden]?nil:customView];
        return NO; //we've done our dirty work
    }

    return YES;
}
  

Ответ №3:

В Swift вы можете переопределить isHidden и настроить view соответствующим образом:

 class PositionHeaderMenuItem: NSMenuItem {
    let customView = SomeCustomView()

    override var isHidden: Bool {
        didSet {
            if isHidden {
                view = nil
            } else {
                view = customView
            }
        }
    }
}
  

Ответ №4:

Мне пришлось переопределить setHidden: метод NSMenuItem и установить нулевую высоту представления, если оно скрыто, вот так:

 - (void) setHidden:(BOOL)flag {

[super setHidden:flag];

NSView *view = [self view];
[view setHidden:flag];

// if our view is hidden, give it a zero height so it won't draw at all
if (flag)
    [view setFrameSize:NSMakeSize([view frame].size.width, 0)];
else {

    [view setFrameSize:NSMakeSize([view frame].size.width, [self menuItemHeight])];
}
  

}

Комментарии:

1. Где menuItemHeight определено? Я не вижу этого в документах для NSMenuItem.

2. Это мой собственный метод (я думаю, что высота по умолчанию равна 19,0, вы можете просто заменить это)