NSSplitView и автозапуск
Как мне использовать ограничения автоматического макета внутри NSSplitView
subview?
My NSSplitView
subview имеет 3 поднабора: topPane
, tableContainer
и bottomPane
, и я устанавливаю ограничения как это:
NSDictionary* views = NSDictionaryOfVariableBindings(topPane, tableContainer, bottomPane);
for (NSView* view in [views allValues]) {
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
}
[myView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[topPane(34)][tableContainer][bottomPane(24)]|"
options:0
metrics:nil
views:views]];
[mySplitView addSubview:myView];
И получил это в консоли:
Unable to simultaneously satisfy constraints:
(
"<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>",
"<NSLayoutConstraint:0x7fd6c4b30910 V:[CPane:0x7fd6c4b2f870(34)]>",
"<NSLayoutConstraint:0x7fd6c4b30770 V:|-(0)-[CPane:0x7fd6c4b2f870] (Names: '|':NSView:0x7fd6c4b22e50 )>",
"<NSLayoutConstraint:0x7fd6c4b212f0 V:[CPane:0x7fd6c4b2fd10]-(0)-| (Names: '|':NSView:0x7fd6c4b22e50 )>",
"<NSLayoutConstraint:0x7fd6c4b2f910 V:[CPane:0x7fd6c4b2f870]-(0)-[NSScrollView:0x7fd6c4b234c0]>",
"<NSLayoutConstraint:0x7fd6c4b21290 V:[CPane:0x7fd6c4b2fd10(24)]>",
"<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>
Я думаю, что <NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>
вызывает это, но я не могу reset авторезистировать маску, потому что NSSplitView
устанавливает ее.
Каков наилучший способ использования автоматической компоновки внутри разметки? И есть ли способ обработать минимальный/максимальный размер разделенного представления subview с автоматическим расположением без NSSplitViewDelegate
?
Ответы
Ответ 1
Я обнаружил, что эта ошибка появляется, если у меня есть панель инструментов в моем окне и управление разделенным представлением любым из этих методов делегата:
splitView:constrainMinCoordinate:ofSubviewAt:
splitView:constrainMaxCoordinate:ofSubviewAt:
splitView:shouldAdjustSizeOfSubview:
Решение было найдено при подключении панели инструментов к окну в windowDidLoad.
Ответ 2
NSSplitView был странным с самого начала, и меня это не удивило бы, если он скоро исчезнет. Попробовав заставить NSSplitView работать с AutoLayout в течение месяца и погрузиться из одной отчаянной атаки в другую, я, наконец, сдался.
Мое решение заключается в не использовать NSSplitView с AutoLayout вообще. Таким образом, либо NSSplitView без Autolayout, либо Autolayout без NSSplitView: это не так сложно, как кажется: просто выложите свои подзоны рядом друг с другом и добавьте NSLayoutConstraints
как IBOutlets
. Затем константы этих ограничений могут быть установлены и изменены с контроллера в коде. С помощью этого подхода вы можете установить начало (отрицательное смещение, чтобы вытащить его из окна), ширину и отношения к другим подзонам - плюс очень легко одушевить ограничения с помощью аниматора вида (когда-либо пытались анимировать NSSplitView?)
Единственное, чего не хватает, - это перетаскивание мышью на разделители, но это может быть реализовано с помощью нескольких строк, отслеживающих mouseEvents в вашем обычном "SplitView".
Там есть пример автозапуска "splitview" от Apple (к сожалению, только по вертикали), и я видел в последнее время по крайней мере один новый проект на github. Хотя для меня я подумал, что было бы легче начать с моего пользовательского решения для моих конкретных приложений, а не пытаться создать что-то очень универсальное (что делает его слишком сложным для обработки).
Изменить: Теперь я завершил свой собственный splitView, который загружает свои подзоны из отдельных наконечников. Нет проблем с ограничениями, нет предупреждений об автозапуске. По сравнению с целым месяцем попытки заставить его работать с NSSplitView, у меня теперь есть рабочий пользовательский splitView, основанный на ограничениях, легко анимативных, созданных всего за один вечер. Я определенно рекомендую воспользоваться этим маршрутом!
Ответ 3
10.8 исправил эту проблему, см. примечания к выпуску.
Вот мое решение для 10.7 (пользовательское разделенное представление):
https://github.com/benuri/HASplitView.git
Ответ 4
Для тех, кто наткнется на это в будущем и ищет начало перехода на замену NSSplitView
на основе ограничений, я написал здесь небольшой проект, который пытается воссоздать часть функций NSSplitView
с помощью Auto Layout:
https://github.com/jwilling/JWSplitView
Это несколько глючит, но это может быть полезной ссылкой на тех, кто хочет идти по этому маршруту.
Ответ 5
Вы не хотите отключать translatesAutoresizingMaskIntoConstraints
вообще. Вы не должны связываться с ограничениями системных представлений. NSSplitView
обрабатывает размер для отдельных видов, и вы, по сути, пытаетесь уничтожить его. Не говоря уже о том, что вы забыли учитывать сплиттер.
Правильный способ установки минимальной или максимальной (или постоянной в этом случае) ширины/высоты на splitview заключается в том, чтобы установить эти вещи в представлениях индивидуально. В частности, если вы делаете это в коде, вам нужно будет использовать 2 отдельных вызова для ограниченийWithVisualFormat, потому что иначе язык визуального формата создаст ограничения между представлениями.
Вы можете сделать все это в IB просто отлично. Вы даже можете установить приоритет каждого представления в режиме разделения, что приведет к изменению размера одного или другого представления, когда это окно сделает, а не равномерно распределяет размер.
Ответ 6
Затем я загружаю все файлы nib и setTranslatesAutoresizingMaskIntoConstraints:NO
.
Так что, возможно, вам следует сначала добавить [mySplitView addSubview:myView];
ваши представления и отключить впоследствии трансляцию маски автоизображения на ограничения, после чего вы добавите свой контраст в myView
.
EDIT:
Хорошо, кажется, я не понимаю, что такое myView.
Вы должны добавить ограничение в subviews, а не в splitview.
[topPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topPane(34)]" options:0 metrics:nil views:views]];
[bottomPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomPane(24)]" options:0 metrics:nil views:views]];
Вам не нужно добавлять граничные ограничения ( "|" в "V: | [topPane (34)]" ), потому что subviews в NSSplitView
уже авторезистируются.
Это приводит к этому, например, для ограничения topPane:
![Screenshout]()
ПРИМЕЧАНИЕ: игнорируйте содержимое подзаголовка, они просто заполнители
Ответ 7
Насколько я ненавижу не согласиться, но ответ Auco не должен быть признан самым высоким. Это никоим образом не помогает в решении проблемы с достаточным объемом работы. На мой взгляд, NSSplitView был только проблемой для тех, кто недостаточно читал документацию.
Реальное решение проблемы, упомянутое здесь, довольно просто: Auto Layout представила новый "API приоритетов для холдинга" в NSSplitView. И, как говорится в документации, установка более низких значений в приоритет удержания подзадачи сделает его более вероятным для получения ширины раньше. Все это можно установить в IB и программно без отчаяния. Требуемый объем работы: 20 секунд.
Ответ 8
Мне потребовалось некоторое время, чтобы очистить автоопределение от предупреждений, но я получил его в IB (несколько splitviews и subviews).
Мой макет выглядит так:
RootView
| | - 1-й NSSplitView (3 вертикальных подсмотра)
| ---- | UIView (слева)
| ---- 2-й NSSplitView (центр и 2 горизонтальных подсмотра)
| --- UIView (вверху)
| --- 3-й NSSplitView
| | --- UIView (слева)
| | | UIView (центр)
| | --- UIView (справа)
| ---- UIView (справа)
Моя проблема заключалась в том, что у меня было 19 предупреждений во всех моих подзаголовках, но мой макет выглядел отлично и работал так, как должно быть.
Через некоторое время я нашел причину моих предупреждений: ограничения внешних представлений в моем первом splitview.
Оба представления (слева и справа) имели ограничение ширины с "width >= 200", а в центральном представлении (2nd splitview) не было ограничений (из-за его минимальной ширины и максимальной ширины, обрабатываемых ее подзонами).
Предупреждения показали мне, что автозапуск хочет сжать мой IB-UI-Layout, потому что рассчитанные минимальные ширины, где меньше, чем мой макет, но я не хотел сжимать его в IB.
Я добавил фиксированное ограничение "width = 200" к обоим внешним представлениям моего первого splitview и проверил "удалить во время сборки".
Теперь мой макет не содержит предупреждений, и все работает так, как должно быть.
Мой вывод:
Я думаю, что проблема с autolayout и splitviews заключается в том, что autolayout не может обрабатывать ограничения ширины subviews. Причина, по которой мы хотим использовать splitviews, заключается в том, что мы хотим динамическую ширину представлений, и мы хотим ее в обоих направлениях, сжимаем и расширяем.
Таким образом, нет ширины <= xxx && width >= xxx. Autolayout может обрабатывать только один из них, и мы получаем предупреждения в IB. Вы можете исправить эту проблему с временным ограничением в IB, который будет удален до выполнения.
Надеюсь, что имеет смысл то, что я написал, но он отлично работал в моем проекте.
PS: Я не мог найти решения до сегодняшнего дня, когда нашел эту тему. Поэтому я думаю, что ваши сообщения вдохновили меня: -)
Ответ 9
Я использовал этот класс в качестве обходного пути, он не идеален (subviews заикается немного), но он разблокировал меня. Я использую этот класс как пользовательский класс внутри каждой области просмотра сплита.
@interface FBSplitPaneView : NSView
@end
@implementation FBSplitPaneView
- (void)setFrame:(NSRect)frame
{
for (NSView *subview in self.subviews) {
subview.frame = self.bounds;
}
[super setFrame:frame];
}
@end