Есть ли подходящий способ справиться с перекрывающимися братьями и сестрами NSView?
Я работаю над приложением Cocoa, и я столкнулся с ситуацией, когда мне хотелось бы, чтобы два объекта NSView перекрывались. У меня есть родительский NSView, который содержит два подзапроса (NSView A и NSView B), каждый из которых может иметь несколько собственных подсетей.
Есть ли способ справиться с подобным перекрытием? NSView B всегда будет "выше" NSView A, поэтому я хочу, чтобы перекрывающиеся части NSView A были замаскированы.
Ответы
Ответ 1
Если ваше приложение имеет размер 10,5, включите слои для просмотров, и он должен просто работать.
Если вы имеете в виду поддержку 10.4 и ниже, вам нужно найти способ не перекрывать представления, потому что совпадающие представления sibling - это поведение undefined. Как говорится в руководстве по программированию:
По соображениям производительности Cocoa не обеспечивает принудительного вырезания среди представлений братьев и сестер или гарантирует правильное поведение недействительности и рисования при совпадении взглядов братьев и сестер. Если вы хотите, чтобы представление было обращено перед другим видом, вы должны сделать вид спереди субвью (или потомок) заднего вида.
Я видел некоторые хаки, которые могут иногда делать это любопытно, но на это не на что можно положиться. Вам нужно либо сделать View A подвид View B, либо сделать одно гигантское представление, которое будет выполнять обе свои обязанности.
Ответ 2
Крис, единственное решение - использовать CALayers. Это определенно единственное решение.
NSViews в OSX (сентябрь 2010) просты в использовании: siblings работают неправильно. Один или другой будет случайным образом отображаться сверху.
Чтобы повторить, проблема заключается в siblings.
Чтобы проверить это: используя NSViews и/или nsimageviews. Сделайте приложение с представлением, которое представляет собой одно большое изображение (1000x1000). В представлении разместите три или четыре маленьких изображения /NSView здесь и там. Теперь добавьте еще одно большое изображение 1000x1000. Создавайте и запускайте приложение повторно - вы увидите, что он просто сломан. Часто нижние (маленькие) слои появляются поверх большого покровного слоя. если вы включите поддержку слоев в NSViews, это не поможет, независимо от того, какую комбинацию вы попробуете. Итак, окончательный тест.
Вам нужно отказаться от NSViews и использовать CALayers и что это.
Единственное раздражение с CALayers заключается в том, что вы не можете использовать IB для настройки своего материала. Вы должны установить все позиции слоя в коде,
yy = [CALayer layer];
yy.frame = CGRectMake(300,300, 300,300);
Сделайте только один NSView, который предназначен только для того, чтобы удерживать ваш первый CALayer (возможно, называемый "сзади" ), а затем просто поместить все ваши CALayers в тыл.
rear = [CALayer layer];
rear.backgroundColor = CGColorCreateGenericRGB( 0.75, 0.75, 0.75, 1.0 );
[yourOnlyNsView setLayer:rear]; // these two lines must be in this order
[yourOnlyNsView setWantsLayer:YES]; // these two lines must be in this order
[rear addSublayer:rr];
[rear addSublayer:yy];
[yy addSublayer:s1];
[yy addSublayer:s2];
[yy addSublayer:s3];
[yy addSublayer:s4];
[rear addSublayer:tt];
[rear addSublayer:ff];
все работает отлично, вы можете вложить и сгруппировать все, что хотите, и все это безупречно работает со всем, что должно быть правильно показано выше/ниже всего, что должно появляться выше/ниже, независимо от сложности вашей структуры. Позже вы можете сделать что-либо для слоев или перетасовать вещи по-разному,
-(void) shuff
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.0f]
forKey:kCATransactionAnimationDuration];
if ..
[rear insertSublayer:ff below:yy];
else
[rear insertSublayer:ff above:yy];
[CATransaction commit];
}
(Единственная причина для раздражающей обертки "в нулевых секундах" для всего, что вы делаете, состоит в том, чтобы предотвратить анимацию, которая предоставляется вам бесплатно - если вы не хотите анимацию!)
Кстати, в этой цитате из Apple,
По соображениям производительности Cocoaне принуждать отсечения к брату взглядов или гарантии недействительность и поведение при рисовании, когда совпадения в виде сестер.
Следующее их предложение...
Если вы хотите, чтобы перед другим видом, вы должны сделать вид спереди подвью (или потомок) заднего вида.
В значительной степени бессмысленна (вы не можете заменить братьев и сестер субтитрами, и очевидная ошибка, описанная в вышеприведенном тесте, все еще существует).
Итак, это CALayers! Наслаждайтесь!
Ответ 3
Есть способ сделать это, не используя CALayers
, и приложение, над которым я работал, может это доказать. Создайте два окна и используйте это:
[mainWindow addChildWindow:otherWindow ordered:NSWindowAbove];
Чтобы удалить "otherWindow", используйте:
[mainWindow removeChildWindow:otherWindow];
[otherWindow orderOut:nil];
И вы, вероятно, захотите взять строку заголовка окна с помощью:
[otherWindow setStyleMask:NSBorderlessWindowMask];
Ответ 4
Чтобы гарантировать, что NSView B
всегда перекрывается NSView A
, убедитесь, что вы используете правильный NSWindowOrderingMode
, когда вы добавляете subview:
[parentView addSubview:B positioned:NSWindowAbove relativeTo:A];
Вы также должны помнить, что скрытые части A не будут запрашиваться для перерисовки, если вид B на 100% непрозрачен.
Если вы перемещаете subviews, вам также необходимо убедиться, что вы вызываете
-setNeedsDisplayInRect:
для областей просмотра, которые вы открываете.
Ответ 5
Как писал Нейт, можно использовать:
self.addSubview(btn2, positioned: NSWindowOrderingMode.Above, relativeTo: btn1)
Однако упорядочение представлений не соблюдается, как только вы просите обоим представлениям перерисовать его через вызов "needDisplay = true"
Братья и сестры не получат вызов drawRect, только прямые иерархии представлений будут.
Обновление 1
Чтобы решить эту проблему, мне пришлось прорываться глубоко, очень глубоко. Вероятно, неделя исследований и Ive распространила мои выводы на несколько статей. Окончательный прорыв в этой статье: http://stylekit.org/blog/2015/12/24/The-odd-case-of-luck/
Обновление 2
Будьте осторожны, хотя понятие трудно понять, но оно работает, и оно отлично работает. Вот конечный результат и код для его поддержки, ссылки на github repo и т.д.: http://stylekit.org/blog/2015/12/30/Graphic-framework-for-OSX/