Примечание : с тех пор, как был задан этот вопрос, дела пошли дальше; смотрите здесь для хорошего недавнего обзора.
Перед автоматическим размещением можно изменить точку привязки слоя вида, не перемещая вид, сохранив рамку, установив точку привязки и восстановив рамку.
В мире автоматической компоновки мы больше не устанавливаем фреймы, но ограничения, похоже, не соответствуют задаче корректировки положения представления туда, где мы хотим его видеть. Вы можете взломать ограничения, чтобы изменить положение своего представления, но при повороте или других событиях изменения размера они снова становятся недействительными.
Следующая яркая идея не работает, так как создает «Неверное сопряжение атрибутов макета (слева и по ширине)»:
layerView.layer.anchorPoint = CGPointMake(1.0, 0.5);
// Some other size-related constraints here which all work fine...
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:layerView
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:20.0]];
Мое намерение здесь было установить левый край layerView
, вид с отрегулированным узловой точкой, до половины его ширины плюс 20 (расстояние я хочу застегивается от левого края надтаблицы).
Можно ли изменить опорную точку, не меняя местоположения вида, в виде с автоматическим макетом? Нужно ли использовать жестко закодированные значения и редактировать ограничение для каждого поворота? Я надеюсь, что нет.
Мне нужно изменить опорную точку, чтобы при применении преобразования к представлению я получал правильный визуальный эффект.
источник
layerView
узнать его ширину? Он придерживается своей правой стороны чему-то другому?//Size-related constraints that work fine
- ширина и высота представления слоя получаются из суперпредставления.Ответы:
[РЕДАКТИРОВАТЬ: Предупреждение: все последующее обсуждение, возможно, будет устаревшим или, по крайней мере, сильно смягченным iOS 8, которая больше не может ошибиться, вызывая компоновку во время применения преобразования представления.]
Autolayout vs. View Transforms
Autolayout не очень хорошо работает с трансформациями вида. Причина, насколько я могу заметить, заключается в том, что вы не должны связываться с фреймом представления, имеющего преобразование (отличное от преобразования идентификаторов по умолчанию) - но это именно то, что делает autolayout. Способ работы autolayout заключается в том, что во
layoutSubviews
время выполнения преодолеваются все ограничения и соответственно устанавливаются кадры всех представлений.Другими словами, ограничения не волшебство; они просто список дел.
layoutSubviews
где список дел делается. И делает это, устанавливая рамки.Я не могу не расценивать это как ошибку. Если я применю это преобразование к представлению:
Я ожидаю увидеть вид с центром в том же месте, что и раньше, и в половине размера. Но, в зависимости от его ограничений, это может быть совсем не то, что я вижу.
[На самом деле, здесь есть второй сюрприз: применение преобразования к представлению немедленно запускает компоновку. Это кажется мне еще одной ошибкой. Или, возможно, это сердце первой ошибки. То, что я ожидал бы, - это иметь возможность уйти с преобразованием по крайней мере до времени компоновки, например, устройство поворачивается - так же, как я могу сойти с анимацией кадра до времени компоновки. Но на самом деле время макета является немедленным, что кажется просто неправильным.]
Решение 1: нет ограничений
Одним из текущих решений является, если я собираюсь применить полупостоянное преобразование к представлению (а не просто как-то временно его покачивать), чтобы удалить все ограничения, влияющие на него. К сожалению, это, как правило, приводит к исчезновению вида с экрана, поскольку автоматическое расположение по-прежнему имеет место, и теперь нет никаких ограничений, указывающих нам, куда поместить представление. Поэтому, в дополнение к удалению ограничений, я установил в
translatesAutoresizingMaskIntoConstraints
YES вид. Представление теперь работает по-старому, фактически не затрагиваемое автоматическим размещением. (Это будет влиять autolayout, очевидно, но неявная маска ограничение автоматического изменения вызывает его поведение , чтобы быть точно так же как это было раньше autolayout.)Решение 2. Используйте только соответствующие ограничения
Если это кажется немного радикальным, другое решение состоит в том, чтобы установить ограничения для правильной работы с предполагаемым преобразованием. Например, если представление имеет размер только по его внутренней фиксированной ширине и высоте и расположено исключительно по его центру, преобразование масштаба будет работать так, как я ожидаю. В этом коде я удаляю существующие ограничения в subview (
otherView
) и заменяю их этими четырьмя ограничениями, придавая ему фиксированную ширину и высоту и закрепляя его чисто по центру. После этого мое масштабное преобразование работает:В результате, если у вас нет ограничений, которые влияют на фрейм представления, автоматическая разметка не коснется фрейма вида - это то, что вам нужно, когда задействовано преобразование.
Решение 3: Используйте Subview
Проблема с обоими вышеупомянутыми решениями состоит в том, что мы теряем преимущества ограничений для позиционирования нашей точки зрения. Итак, вот решение, которое решает это. Начните с невидимого представления, работа которого состоит исключительно в том, чтобы выступать в роли хоста, и используйте ограничения для его позиционирования. Внутри этого, поместите реальный взгляд как подпредставление. Используйте ограничения, чтобы расположить подпредставление в представлении хоста, но ограничьте эти ограничения ограничениями, которые не будут сопротивляться, когда мы применяем преобразование.
Вот иллюстрация:
Белый вид - это вид хоста; Вы должны притворяться, что оно прозрачное и, следовательно, невидимое. Красный вид - это его подпредставление, расположенное путем прикрепления его центра к центру основного вида. Теперь мы можем без проблем масштабировать и вращать красный вид вокруг его центра, и на самом деле иллюстрация показывает, что мы сделали это:
Между тем, ограничения на представление хоста сохраняют его в нужном месте, когда мы вращаем устройство.
Решение 4. Вместо этого используйте преобразования слоев
Вместо преобразований вида используйте преобразования слоя, которые не вызывают компоновку и, следовательно, не вызывают немедленного конфликта с ограничениями.
Например, эта простая «пульсирующая» анимация вида может полностью сломаться при автоматическом размещении:
Несмотря на то, что в конце не было никаких изменений в размере представления, просто установление его
transform
расположения вызывает, и ограничения могут заставить представление прыгать вокруг. (Это похоже на ошибку или что?) Но если мы сделаем то же самое с Core Animation (используя CABasicAnimation и применив анимацию к слою представления), макет не произойдет, и он будет работать нормально:источник
У меня был похожий Isuue, и я только что услышал Back от команды Autolayout в Apple. Они предлагают использовать подход «Подход к представлению контейнера», но они создают подкласс UIView, чтобы перезаписывать layoutSubviews и применять там собственный код макета. Это работает как шарм.
Заголовочный файл выглядит так, что вы можете связать выбранное вами подпредставление напрямую из Interface Builder
и файл m применяет специальный код так:
Как вы можете видеть, он захватывает центральную точку просмотра при первом вызове и повторно использует эту позицию в последующих вызовах, чтобы разместить представление соответствующим образом. Это переписывает код Autolayout в том смысле, что это происходит после [super layoutSubviews]; который содержит код разметки.
Таким образом, больше нет необходимости избегать Autolayout, но вы можете создать свою собственную autolayout, когда поведение по умолчанию больше не подходит. Конечно, вы можете применять более сложные вещи, чем в этом примере, но это было все, что мне было нужно, так как мое приложение может использовать только портретный режим.
источник
layoutSubviews
. Я бы просто добавил, что Apple здесь просто заставляет вас делать то, что, я думаю, они должны были делать (в своей реализации Autolayout) все время.Я нахожу простой способ. И это работает на iOS 8 и iOS 9.
Как настроить anchorPoint при использовании фрейм-макета:
Когда вы настраиваете привязку вида с помощью автоматического макета, вы делаете то же самое, но с ограничениями. Когда anchorPoint изменится с (0,5, 0,5) на (1, 0,5), layerView переместится влево на расстояние, равное половине длины ширины вида, поэтому вам необходимо это компенсировать.
Я не понимаю ограничение в вопросе. Итак, предположим, что вы добавляете ограничение centerX относительно superView centerX с константой: layerView.centerX = superView.centerX + constant
источник
Если вы используете автоматическую разметку, то я не вижу, как ручная настройка позиции будет служить в долгосрочной перспективе, потому что в конечном итоге автоматическая разметка приведет к засорению значения позиции, которое вы установили, при вычислении собственной разметки.
Скорее, необходимо изменить сами ограничения макета, чтобы компенсировать изменения, произведенные установкой anchorPoint. Следующая функция делает это для нетрансформированных представлений.
Я признаю, что это, вероятно, не все, на что вы надеялись, поскольку обычно единственная причина, по которой вы хотите изменить anchorPoint, - это установить преобразование. Это потребовало бы более сложной функции, которая обновляет ограничения макета, чтобы отразить все изменения кадра, которые могут быть вызваны самим свойством transform. Это сложно, потому что преобразования могут многое сделать для кадра. Преобразование масштабирования или поворота сделает кадр больше, поэтому нам нужно обновить любые ограничения ширины или высоты и т. Д.
Если вы используете преобразование только для временной анимации, то вышеописанного может быть достаточно, поскольку я не верю, что автоматическая компоновка не позволит анимации в полете представить изображения, которые представляют собой чисто временные нарушения ограничений.
источник
tl: dr: Вы можете создать выход для одного из ограничений, чтобы его можно было удалить и снова добавить.
Я создал новый проект и добавил вид с фиксированным размером в центре. Ограничения показаны на рисунке ниже.
Затем я добавил выход для вида, который будет вращаться, и для ограничения выравнивания центра х.
Позже
viewDidAppear
я вычисляю новую опорную точкуЗатем я удаляю ограничение, для которого у меня есть выход, создаю новое смещение и снова добавляю его. После этого я сообщаю представлению с измененным ограничением, что оно должно обновить ограничения.
Наконец, я просто добавляю анимацию вращения к вращающемуся виду.
Вращающийся слой выглядит так, как будто он остается в центре (что и должно быть) даже при вращении устройства или иным образом, что заставляет его обновлять ограничения. Новое ограничение и измененная точка привязки визуально отменяют друг друга.
источник
Мое текущее решение состоит в том, чтобы вручную отрегулировать положение слоя в
viewDidLayoutSubviews
. Этот код также можно использоватьlayoutSubviews
для подкласса представления, но в моем случае мое представление является представлением верхнего уровня внутри контроллера представления, поэтому это означало, что мне не нужно было создавать подкласс UIView.Кажется, слишком много усилий, поэтому другие ответы приветствуются.
источник
Вдохновленный ответом моего Мэтта, я решил попробовать другой подход. Можно использовать контейнерное представление с соответствующими ограничениями. Вид с модифицированной якорной точкой может быть помещен в поле зрения контейнера, с помощью автоматического изменения маски и явной настройки кадра так же, как в старые времена.
Это работает удовольствие для моей ситуации в любом случае. Представления настроены здесь в viewDidLoad:
Неважно, что кадры для красного вида на этом этапе равны нулю из-за маски авторазмера на зеленом виде.
Я добавил преобразование вращения в метод действия, и это было результатом:
Казалось, что он теряет себя во время вращения устройства, поэтому я добавил это в метод viewDidLayoutSubviews:
источник
view.layer
покое и делать всю свою работу в подслоеview.layer
. Другими словами, представление будет просто хостом, а все преобразования чертежа и подслоя и т. Д. Будут иметь уровень вниз, не подверженный влиянию ограничений.Я думаю, что вы победили цель автоматического размещения с помощью этого метода. Вы упомянули, что ширина и правый край зависят от суперпредставления, так почему бы просто не добавить ограничения вдоль этого мышления?
Потеряйте парадигму anchorPoint / transform и попробуйте:
Эти
NSLayoutAttributeRight
средства ограничений в точности , какanchorPoint = CGPointMake(1.0, 0.5)
, иNSLayoutAttributeWidth
ограничение примерно соответствуют вашему предыдущему коду - хNSLayoutAttributeLeft
.источник
anchorPoint
, моя точка зрения, вы не должны использовать его для измерений. Система автоматического размещения UIView должна быть независимой от преобразований CALayer. So UIView: макет, CALayer: внешний вид / анимацияviewDidLayoutSubviews
должен исправить это;position
всегда идет вместе сanchorPoint
. Мой ответ просто показывает, как определить ограничение для преобразования идентичности.Этот вопрос и ответы вдохновили меня на то, чтобы решить собственные проблемы с Autolayout и масштабированием, но с помощью scrollviews. Я создал пример моего решения на github:
https://github.com/hansdesmedt/AutoLayout-scrollview-scale
Это пример UIScrollView с пользовательской страницей, полностью выполненной в AutoLayout и масштабируемой (CATransform3DMakeScale) при длительном нажатии и нажатии для увеличения. iOS 6 и 7 совместимы.
источник
Это большая тема, и я не прочитал все комментарии, но столкнулся с той же проблемой.
У меня был вид из XIB с autolayout. И я хотел обновить его свойство transform. Внедрение представления в представление контейнера не решает мою проблему, потому что автоматическое расположение действовало странно на представление контейнера. Вот почему я только что добавил второе представление контейнера, чтобы оно содержало представление контейнера, которое содержит мое представление и применяет к нему преобразования.
источник
tl; dr Допустим, вы изменили опорную точку на (0, 0). Опорная точка теперь в левом верхнем углу. Каждый раз, когда вы видите центр слова в автоматическом макете, вы должны думать, что слева вверху .
Когда вы настраиваете свою anchorPoint, вы просто меняете семантику AutoLayout. Автоматическая разметка не будет мешать вашей anchorPoint, и наоборот. Если вы этого не понимаете, у вас будет плохое время .
Пример:
Рисунок А. узловая точка модификации Нет
Рисунок B. Опорная точка изменена на верхний левый
Рисунок A и рисунок B выглядят одинаково. Ничего не изменилось. Просто определение того, на что ссылается центр, изменилось.
источник