2012-06-29 4 views
21

Как следует использовать ограничения автоматической компоновки внутри NSSplitView subview?NSSplitView и автоопределение

Мой NSSplitView подтаблицы имеет 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)]> причины этого, но я не могу сбросить маску авторезистировки, потому что ее устанавливает NSSplitView.

Каков наилучший способ использования автоматической компоновки внутри сплит-представления? И есть ли способ обработать минимальный/максимальный размер разделенного вида subview с автоматической компоновкой без NSSplitViewDelegate?

+0

Одинаковая проблема здесь. Я выложил все в IB, а не программно, но имел аналогичный вывод отладки, включая 'NSAutoresizingMaskLayoutConstraint'. –

+1

Это кажется фиксированным в 10.8, но сломан, как вы заметили, под 10.7. В 10.8 вы можете установить минимальные высоты и ширину представлений контента в режиме разделения в Xcode (4.5.2 в любом случае). Невозможно сделать это в 10.7, а приложения с этим, созданные в 10.8, все еще не работают правильно в 10.7 – Dad

+0

Работает вообще с 10.8+, но ограничения должны быть указаны между subviews для большинства просмотров - не supre - или вы получите * Unable для одновременного удовлетворения * ошибки .. – Jay

ответ

0

После этого загружаю все файлы с пивом и setTranslatesAutoresizingMaskIntoConstraints:NO.

Итак, возможно, вы должны сначала добавить свои взгляды и отключить перевод маски автозапуска на ограничения, после чего вы добавите свой контраст в myView.

EDIT:

Хорошо, кажется, я missunderstand в 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)]"), так как подвиды в NSSplitView уже автоматического изменения.

Это приводит к этому, например, для topPane ограничения:

Screenshout

Примечание: игнорировать содержание подвид, они просто заполнителей

+0

Если я устанавливаю 'translatesAutoresizingMaskIntoConstraints' на' NO' для 'myView', split view не будет обрабатывать его размер - он не работает с автозапуском. – Dmitry

1

Вы не хотите, чтобы отключить translatesAutoresizingMaskIntoConstraints вообще. Вы не должны связываться с ограничениями системных представлений. NSSplitView обрабатывает размеры для отдельных видов, и вы по существу пытаетесь сорвать его контроль. Не говоря уже о том, что вы забыли учитывать сплиттер.

Правильный способ установки минимальной или максимальной (или постоянной в этом случае) ширины/высоты в режиме splitview заключается в том, чтобы установить эти вещи в представлениях индивидуально. В частности, если вы делаете это в коде, вам нужно будет использовать 2 отдельных вызова для ограниченийWithVisualFormat, потому что иначе язык визуального формата создаст ограничения между представлениями.

Вы можете сделать все это в ИБ просто отлично. Вы даже можете установить приоритет каждого представления в режиме разделения, что приведет к изменению размера одного или другого представления, когда это делает окно, а не равномерно распределяет размер.

+0

Интересно услышать, как вы предлагаете сделать это все в IB с включенным AutoLayout .... – Dad

+0

на самом деле невозможно в 10.7 - элемент управления для ограничения ширины в представлении содержимого NSSplitView отключен в Xcode 4.5.2 под номером 10.7 и если вы установите его в Xcode на 10.8, а затем запустите приложение на 10.7, он сломает это ограничение в пользу NSAutoresizingMaskLayerConstraint в 10.7 и поэтому не будет работать. – Dad

4

NSSplitView был странным с самого начала, и меня это не удивит, если он скоро исчезнет. Попытавшись заставить NSSplitView работать с AutoLayout в течение месяца и опуститься от одной отчаянной атаки на другую, я, наконец, сдался.

Мое решение - Не использовать NSSplitView с AutoLayout. Таким образом, либо NSSplitView без Autolayout, либо Autolayout без NSSplitView: это не так сложно, как кажется: просто выложите свои подзоны рядом друг с другом и добавьте NSLayoutConstraints как IBOutlets. Затем константы этих ограничений могут быть установлены и изменены с контроллера в коде. С помощью этого подхода вы можете установить начало координат (отрицательное смещение, чтобы вывести его из окна), ширину и отношения к другим подзонам - плюс очень легко одушевить ограничения с помощью аниматора вида (когда-либо пытался до анимировать NSSplitView?)

Единственное, чего не хватает, - это перетаскивание мышью на разделителях, но это может быть реализовано с помощью нескольких линий, отслеживающих mouseEvents в вашем обычном «SplitView».

Есть пример автозапуска «splitview» от Apple (к сожалению, только по вертикали), и в последнее время я видел по крайней мере один новый проект в github. Хотя для меня, я думал, будет легче начать с моего пользовательского решения для конкретных потребностей моего приложения, вместо того, чтобы пытаться создать что-то очень универсальное (что делает его слишком сложным для обработки).

Редактировать: Теперь я выполнил свой собственный splitView, который загружает свои подзоны из отдельных наконечников. Нет проблем с ограничениями, нет предупреждений об автозапуске. По сравнению с целым месяцем попытки заставить его работать с NSSplitView, у меня теперь есть рабочий пользовательский splitView, основанный на ограничениях, легко анимативных, созданных всего за один вечер. Я определенно рекомендую воспользоваться этим маршрутом!

+0

Можете ли вы поделиться своим пользовательским кодом splitView? –

+1

@ Ben-Uri: У меня есть небольшой проект в моем [ответе] (http://stackoverflow.com/a/13964486/456851), который может вам пригодиться. –

+0

Глупости - работает как бриз с AL в 10.8+ – Jay

0

Насколько я ненавижу не согласиться, но ответ Ауко должен быть самым высоким. Это никоим образом не помогает в решении проблемы с достаточным объемом работы. На мой взгляд, NSSplitView был только проблемой для тех, кто недостаточно читал документацию.

Реальное решение проблемы, упомянутое здесь, довольно просто: Auto Layout представила новый «API приоритетов удержания» на NSSplitView. И, как говорится в документации, установка более низких значений в приоритет удержания подзадачи сделает его более вероятным для получения ширины раньше. Все это можно установить в IB и программно без отчаяния. Необходимый объем работы: 20 секунд ок.

+1

Этот ответ был бы более полезен, если бы он просто ответил на вопрос, а не демонстрировал такое презрение к другим ответчикам и вопрошающим. Я дам вам +1 за ответ и -1 за грубость, поэтому они отменяют друг друга. –

+1

@Jacque: Если бы вы также прочитали документацию, вы бы увидели, что приоритеты при хранении работают только на OS X 10.8+. Не нужно быть бесцеремонным против других, когда они, возможно, думают о обратной совместимости, а вы не были. –

+1

@Jacque: Возможно, вы правы, если имеете дело с очень простой компоновкой, например, двумя текстовыми окнами в качестве подзонов одного splitView. Но как только вам нужно иметь дело со сложными макетированными подзонами, настройка приоритетов размещения не поможет: контент в splitView, который использует autolayout, создает ошибки автоопределения, поскольку он конфликтует с авторезистирующими масками. Анимация SplitViews - это боль в прикладе, потому что вам нужно рассчитать фреймы, которые не используются при использовании автоматической компоновки. Есть гораздо больше проблем, чем вы можете решить, просто придерживаясь приоритетов. – auco

3

10.8 исправлена ​​эта проблема, см. Примечания к выпуску.

Вот мое решение для 10.7 (пользовательского режима просмотра): https://github.com/benuri/HASplitView.git

7

я узнал, что эта ошибка появляется, если у меня есть панели в моем окне и управления видом расщепленный любой из этих делегированных методов:

splitView:constrainMinCoordinate:ofSubviewAt: 
splitView:constrainMaxCoordinate:ofSubviewAt: 
splitView:shouldAdjustSizeOfSubview: 

Решение было найдено при установке панели инструментов в окно WindowDidLoad.

+0

У меня была такая же проблема с NSTabView, сняв флажок «Видимый при запуске» на панели инструментов, а затем сделав ее видимой в 'windowDidLoad', избавился от глупых предупреждений. Спасибо за подсказку. – DarkDust

+0

В режиме автоматического разбиения на макет с ограничениями ширины min/max у меня была та же проблема. Устранение всех этих трех делегатских методов разрешило это. –

+2

Много дезинформации по этому вопросу. Этот ответ на правильном пути, но бизнес на панели инструментов - это красная селедка. Эта проблема задокументирована в примечаниях к выпуску AppKit (https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKitOlderNotes/index.html#10_11SplitView); некоторые из методов «NSSplitViewDelegate» не очень хорошо работают с автозапуском и не должны использоваться. Вместо этого настройте соответствующие ограничения на 'NSView' непосредственно под 'NSSplitView', и он должен работать нормально, не регистрируясь. – bhaller

3

Для тех, кто натыкается на это в будущем и ищет прыгающий в основе ограничений NSSplitView замен, я написал небольшой проект здесь, что попытки воссоздать часть функций NSSplitView «s с помощью Auto Layout:

https://github.com/jwilling/JWSplitView

это несколько багги, но это может быть полезным справочником для тех, кто хочет идти по этому пути.

0

Мне потребовалось некоторое время, чтобы очистить автозапуск от предупреждений, но я получил обработку в IB (несколько разделов и подвид).

Моя раскладка выглядит следующим образом:

RootView
    | - 1-й NSSplitView (3 вертикальных подвиды)
            | ---- UIView (слева)
            | ---- 2nd NSSplitView (центр & 2 горизонтальные подвиды)
                      | --- UIView (вверху)
                      | --- третьего NSSplitView (внизу & 3 вертикальных подземелья)
                              | --- UIView (слева)
                              | --- UIView (в центре)
                              | --- UIView (справа)
            | ---- UIView (справа)

Моя проблема была, что у меня было 19 предупреждений во всех моих подзаголовках, но мой макет выглядел прекрасно и работал так, как должно быть. Через некоторое время я обнаружил причину моих предупреждений: ограничения внешних представлений в моем первом splitview.

Оба вида (слева и справа) имеют ограничение ширины с шириной> 200 дюймов, а в центральном (2-й раскол) не было ограничений (поскольку его минимальная ширина и максимальная ширина, обрабатываемые ее подзонами) ,

Предупреждения показали мне, что автозапуск хочет сжать мой IB-UI-Layout, потому что рассчитанные минимальные ширины, где меньше, чем мой макет, но я не хотел сокращать его в IB.

Я добавил фиксированное ограничение «width = 200» к обоим внешним областям моего первого splitview и проверил «удалить во время сборки».

Теперь мой макет не содержит предупреждений, и все работает так, как должно быть.

Мой вывод:

Я думаю, что проблема с autolayout и splitviews что autolayout не может обрабатывать ширины ограничений подвидов. Причина, по которой мы хотим использовать splitviews, заключается в том, что мы хотим динамическую ширину представлений, и мы хотим ее в обоих направлениях, сжимаем и расширяем.

Таким образом, нет ширины < = xxx & & ширина> = xxx. Autolayout может обрабатывать только один из них, и мы получаем предупреждения в IB. Вы можете исправить эту проблему с временным ограничением в IB, которое будет удалено до выполнения.

Надеюсь, имеет смысл то, что я написал, но в моем проекте это отлично работало.

PS: Я не удалось найти какое-либо решение до сегодняшнего дня, когда я нашел эту тему .. так что я думаю, ваши посты вдохновило меня :-)

0

Я использовал этот класс в качестве обходного пути, он не совершенен (подвиды заикание немного), но он разблокировал меня. Я использую этот класс как пользовательский класс внутри каждой области просмотра сплита.

@interface FBSplitPaneView : NSView 

@end 

@implementation FBSplitPaneView 

- (void)setFrame:(NSRect)frame 
{ 
    for (NSView *subview in self.subviews) { 
    subview.frame = self.bounds; 
    } 
    [super setFrame:frame]; 
} 

@end 
Смежные вопросы