Подтвердить что ты не робот

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?

4b9b3361

Ответ 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