#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, вы можете просто заменить это)