NSImageView всегда отображается поверх любого другого вида - PullRequest
0 голосов
/ 28 мая 2018

Я работаю над приложением базы данных с графическим редактором, очень похожим на Interface Builder.Однако, в отличие от IB, этот редактор можно переключать из режима редактора в режим реального времени, где пользовательский интерфейс полностью работоспособен (можно нажимать кнопки, редактировать текст и т. Д.). Для этого графический редактор использует стандартные классы интерфейса Appkit -NSButton, NSTextView и т. Д. Сам редактор реализован с помощью пользовательского подкласса NSView.Все элементы пользовательского интерфейса являются подпредставлениями этого пользовательского NSView, новые элементы добавляются с помощью метода addSubview:, что делает новый элемент наиболее видимым элементом (обратите внимание - представления не имеют слоистой подложки, а только обычные представления).Пользователь также может использовать команды Bring-to-Front и Send-to-Back для изменения порядка подпредставлений.В этом фильме показаны два перекрывающихся элемента NSButton (в иллюстративных целях, конечно, обычно вы бы никогда не перекрывали их) и как программа может переупорядочить подпредставление, чтобы изменить Z-порядок элементов пользовательского интерфейса.

Bring-to-Front, Send-to-Back

Проблема в том, что это работает со всеми типами элементов интерфейса , за исключением NSImageView.В предыдущем фильме есть два элемента: NSButton и NSImageView.NSButton фактически все время находится «сверху», элемент NSImageView должен появляться за кнопкой, но независимо от порядка подпредставлений NSImageView всегда появляется сверху.

NSImageView always on top

Если есть два перекрывающихся объекта NSImageView, видимый порядок расположения между ними непредсказуем, но они всегда будут появляться над всеми другими объектами, независимо от порядка подпредставлений.

Возможно, полезная подсказка в том, что если я реализую свой собственный пользовательский вид, который рисует изображение непосредственно в его методе drawRect:, это прекрасно работает.Так что это одно из возможных решений, но я неохотно, потому что это означает повторную реализацию большого количества полезных функций, о которых обычно заботится NSImageView, некоторые из которых довольно сложны, например, поддерживают анимированный GIF-дисплей.Кроме этой проблемы с многоуровневым / z-порядком, все остальное в NSImageView работает нормально.

Возможно, NSImageView использует поддержку слоев без моего запроса, поэтому он не смешивается должным образом с другими моими объектами?Я не могу найти документацию, которая указывает на это.Я не связываюсь с платформой QuartzCore.

Вот код, который добавляет элемент NSImageView как подпредставление к представлению графического редактора.

- (void)objectDidAppearBelow:(NSView *)nextView
{
    FormView * formView = [FormWindowController currentFormView]; // get view element will be placed into
    NSScrollView * imageContainer = [[NSScrollView alloc] initWithFrame:insideBorderRect];
    ImageView * ixView = [[ImageView alloc] initWithFrame:[self insideFormObjectBorder:objectRectangle]];
    [ixView setOwnerObject:self];
    [imageContainer setDocumentView:ixView];    
    [imageContainer setAutoresizesSubviews:YES];
    [shapeView addSubview:imageContainer Below:nextView];
    imageDocumentView = ixView; // save weak reference to image view so it can be manipulated
}

В других местах есть почти идентичный коддля NSButton (в нескольких вариантах для кнопок, переключателей и т. д.), NSTextView, NSTableView (для списков и матриц), NSSlider, NSScroller, NSSegmentedControl и даже WebView.Все остальные корректно работают с перекрывающимися объектами, включая WebView, только NSImageView не работает должным образом.

Для справки: # 429 в трекере проблем Panorama X.

1 Ответ

0 голосов
/ 20 июня 2018

Я обсуждал эту проблему с инженерами Apple на WWDC 2018. Оказывается, что, как я подозревал, в некоторых случаях Appkit будет использовать поддержку слоев для NSImageView, даже если вы не просили об этом!Поэтому лучшее решение - это переключить все виды на подложку слоя (что произойдет автоматически с Mojave).

В данном конкретном случае NSImageView находился внутри NSScrollView, о котором я не упомянул, потому что не думалэто было важно (мое плохо).Оказывается, это тот случай, когда Appkit считает, что было бы неплохо использовать поддержку слоев (для оптимизации прокрутки).Итак, еще один способ исправить это - создать подкласс NSImageView (что я уже сделал по другим причинам) и добавить этот метод (написанный на месте инженером Apple, который предпочитает оставаться некредитованным).

+ (BOOL)isCompatibleWithResponsiveScrolling {
    if (NSAppKitVersionNumber <= 1561. /* NSAppKitVersionNumber10_13 */) {
        return NO;
    } else {
        return YES;
    }
}

Я был уверен, что это все часть публичного, документированного API, хотя документация минимальна (неожиданный сюрприз).В комментариях к выпуску Что нового в OS X 10.9 обсуждается адаптивная прокрутка.Проверка с помощью NSAppKitVersionNumber заключается в том, чтобы отключить этот патч при работе в Mojave, поскольку все поддерживается слоем.

...