2013-06-27 1 views
1

Итак, у меня есть два прямоугольных вида и вид, который соединяет их вместе. См. Диаграмму http://cl.ly/image/340Q1l381b3LАвтоматическая компоновка и центрирование представления между двумя другими видами

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

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

[NSLayoutConstraint 
constraintWithItem:redView 
attribute:NSLayoutAttributeCenterY 
relatedBy:NSLayoutRelationGreaterThanOrEqual 
toItem:greenView 
attribute:NSLayoutAttributeBottom 
multiplier:1.0f 
constant:0.0f]; 

[NSLayoutConstraint 
constraintWithItem:redView 
attribute:NSLayoutAttributeCenterY 
relatedBy:NSLayoutRelationLessThanOrEqual 
toItem:greenView 
attribute:NSLayoutAttributeTop 
multiplier:1.0f 
constant:0.0f]; 

Но это приводит к

2013-06-26 22: 13: 27.493 MiniMeasure [25896: 303] Невозможно одновременно удовлетворяют ограничениям: ( «NSLayoutConstraint: 0x1002cebf0 RedView: 0x1002cdf90. centerY> = Greenview: 0x1018a34c0.bottom», "NSLayoutConstraint: 0x1002cf720 RedView: 0x1002cdf90.centerY < = Greenview: 0x1018a34c0.top", "NSLayoutConstraint: 0x1002bb1e0 V: [Greenview: 0x1018a34c0 (157)]" ) будет пытаться восстановить путем нарушения ограничений NSLa youtConstraint: 0x1002bb1e0 V: [Greenview: 0x1018a34c0 (157)]

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

Любые мысли или предложения?

Спасибо!

+0

Вы можете получить зеленые, где вы их ожидаете? Они двигаются? – uchuugaka

+0

Да. Зеленые можно перемещать и изменять размер, используя только ограничения. Это красное представление, что у меня проблемы с ограничением. –

+0

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

ответ

0

Основываясь на комментариях, одним из решений является не использование автоматического макета для красного прямоугольника, а простое использование drawRect в супер-представлении или в подсмотре, который является тем же самым фреймом, что и супер-просмотр.

Первого использование КВО, чтобы получать уведомления об изменениях в зеленых прямоугольники кадров наших границ (в случае необходимости для реализации)

изменился?

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

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

Куда удастся, сравнивая их края.

Псевдокод Если unionRect.size.x> (greenRect1.size.x + greenRect2.size.x) И unionRect.size.y < (greenRect1.size.y + greenRect2.size.y) Тогда нарисуйте красный прямоугольник между ними по горизонтали. Теперь вычислите прямоугольник для красного прямоугольника.

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

Я не уверен, что все принадлежит авто макету для объема работы, сложности и потенциального обфускации смысла.

+0

Так что в настоящее время у меня есть рабочее решение, просто установив рамку на красный прямоугольник, но все мое приложение - это авто-макет и он просто чувствовал себя грязным. Я просто задавался вопросом, не пропустил ли я что-то, но я думаю, что вы правы ... что использование авто-макета в этом контексте просто добавит сложности. Спасибо за ответ! –

+0

Но взгляните на сообщение Роба. Это поучительно. – uchuugaka

+0

Но я думаю, что трюк - это прагматизм. Apple нажимает автоматическую компоновку и уходит, что не всегда является лучшим решением для всего. Я тоже это изучаю. – uchuugaka

11

Вы можете получить то, что хотите, с автозагрузкой. Демонстрация:

demo

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

enter image description here

Итак, как я сделал это ?

Прежде всего, существует пять видов. Имеется представление содержимого окна, два перетаскиваемых зеленых вида, текстовое поле («Центр») и вид с зазором загар. Перетаскиваемые представления, текстовое поле и разделитель являются прямым подзоном просмотра содержимого окна. В частности, текстовое поле не подглядывание проставки.

Во-вторых, я должен установить приоритет некоторых ограничений, поэтому я определить вспомогательную функцию:

static NSLayoutConstraint *constraintWithPriority(NSLayoutConstraint *constraint, 
    NSLayoutPriority priority) 
{ 
    constraint.priority = priority; 
    return constraint; 
} 

Далее я создаю левый перемещаемой вид. Я установил ограничения для его X-позиции и ширины, высоты и положения Y.

- (void)createLeftView { 
    leftView = [[DraggableView alloc] init]; 
    leftView.translatesAutoresizingMaskIntoConstraints = NO; 
    [rootView addSubview:leftView]; 

    NSDictionary *views = NSDictionaryOfVariableBindings(leftView); 
    [rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|-(20)-[leftView(80)]" 
     options:0 metrics:nil views:views]]; 
    [leftView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:[leftView(120)]" 
     options:0 metrics:nil views:views]]; 
    leftView.yConstraint = [NSLayoutConstraint 
     constraintWithItem:leftView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationEqual 
     toItem:rootView attribute:NSLayoutAttributeTop 
     multiplier:1 constant:20]; 
    [rootView addConstraint:leftView.yConstraint]; 
} 

Обратите внимание, что мой DraggableView класс обрабатывает мышь тащит, регулируя проницаемость ее yConstraint. Поскольку мне нужен доступ к ограничению Top, я устанавливаю его непосредственно вместо использования визуального формата.

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

- (void)createRightView { 
    rightView = [[DraggableView alloc] init]; 
    rightView.translatesAutoresizingMaskIntoConstraints = NO; 
    [rootView addSubview:rightView]; 

    NSDictionary *views = NSDictionaryOfVariableBindings(rightView); 
    [rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:[rightView(80)]-(20)-|" 
     options:0 metrics:nil views:views]]; 
    [rightView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:[rightView(120)]" 
     options:0 metrics:nil views:views]]; 
    rightView.yConstraint = [NSLayoutConstraint 
     constraintWithItem:rightView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationEqual 
     toItem:rootView attribute:NSLayoutAttributeTop 
     multiplier:1 constant:20]; 
    [rootView addConstraint:rightView.yConstraint]; 
} 

Теперь наступает сложная часть. Я создаю дополнительный вид, который я называю разделителем. Я оставил вид видимым, чтобы было легче понять, как работает эта демонстрация. Обычно вы делаете спейсер скрытым; скрытые виды все еще участвуют в макете.

- (void)createSpacerView { 
    spacerView = [[SpacerView alloc] init]; 
    spacerView.translatesAutoresizingMaskIntoConstraints = NO; 
    [rootView addSubview:spacerView]; 

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

NSDictionary *views = NSDictionaryOfVariableBindings(leftView, rightView, spacerView); 
    [rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:[leftView][spacerView][rightView]" 
     options:0 metrics:nil views:views]]; 

Далее, мы ограничить верхний и нижний край спейсера к равным зрения корневого верхнего и нижнего краев, но с приоритетом 1 (чрезвычайно низкий приоритет):

[rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:|-([email protected])-[spacerView]-([email protected])-|" 
     options:0 metrics:nil views:views]]; 

Затем мы дополнительно ограничить распорные-х верхний край, чтобы быть больше или равно верхние края обоих верхних краев перетаскиваемую Views', с приоритетом 2 (почти как крайне низкий):

[rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationGreaterThanOrEqual 
     toItem:leftView attribute:NSLayoutAttributeTop 
     multiplier:1 constant:0], 2)]; 
    [rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationGreaterThanOrEqual 
     toItem:rightView attribute:NSLayoutAttributeTop multiplier:1 constant:0], 2)]; 

так верхний край распорной имеет три Ограничения:

  • spacerView.top == rootView.top с приоритетом 1
  • spacerView.top> = leftView.топ с приоритетом 2
  • spacerView.top> = rightView.top с приоритетом 2

Эти ограничения объединяются, чтобы поместить верхний край спейсера, как высоко, как это возможно, не будучи выше верхних краев обеих Draggable Views'. Таким образом, верхний край проставки будет равен нижнему из верхних краев перетаскиваемых видов.

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

Мы создали аналогичные ограничения на нижнем крае спейсера по:

[rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeBottom 
     relatedBy:NSLayoutRelationLessThanOrEqual 
     toItem:leftView attribute:NSLayoutAttributeBottom 
     multiplier:1 constant:0], 2)]; 
    [rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeBottom 
     relatedBy:NSLayoutRelationLessThanOrEqual 
     toItem:rightView attribute:NSLayoutAttributeBottom 
     multiplier:1 constant:0], 2)]; 
} 

Таким образом, распорка всегда будет занимать вертикальное перекрытие перемещаемых взглядов, если есть перекрытие. Если нет перекрытия, автомакет будет разорвать некоторое ограничение, чтобы не дать разделителю отрицательную высоту. Проставка будет иметь высоту 0, прикрепленную к одному из ближайших краев перетаскиваемых видов.

Наконец, я создал текстовое поле, чтобы оставаться в центре по горизонтали и по вертикали над распоркой:

- (void)createMiddleView { 
    middleView = [[NSTextField alloc] init]; 
    middleView.translatesAutoresizingMaskIntoConstraints = NO; 
    middleView.stringValue = @"Center"; 
    [middleView setEditable:NO]; 
    [middleView setSelectable:NO]; 
    [rootView addSubview:middleView]; 

    [rootView addConstraint:[NSLayoutConstraint 
     constraintWithItem:middleView attribute:NSLayoutAttributeCenterX 
     relatedBy:NSLayoutRelationEqual 
     toItem:spacerView attribute:NSLayoutAttributeCenterX 
     multiplier:1 constant:0]]; 
    [rootView addConstraint:[NSLayoutConstraint 
     constraintWithItem:middleView attribute:NSLayoutAttributeCenterY 
     relatedBy:NSLayoutRelationEqual 
     toItem:spacerView attribute:NSLayoutAttributeCenterY 
     multiplier:1 constant:0]]; 
} 

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

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

Вы можете найти мой полный исходный код проекта демо-проекта in this github repository. Я создал проект в Xcode 5-DP2.

+0

Удивительный учебник. Было бы потрясающе с версией Xcode 4 ...;) К сожалению, это подчеркивает, насколько на самом деле сложна автоматическая компоновка, в немалой степени, насколько она еще молода в Cocoa. Конечно, CoreData выглядит просто. – uchuugaka

+0

Исходные файлы должны работать, если вы скопируете их в новый проект, созданный в Xcode 4. –

+0

True true. Это пуповины, которые сгорблены. BTW +100 для gifs: D – uchuugaka