Я обновляю старое приложение, AdBannerView
и когда оно не появляется, оно исчезает с экрана. Когда есть реклама, она скользит по экрану. Основные вещи.
По старому стилю я установил кадр в анимационном блоке. В новом стиле у меня есть ограничение IBOutlet
auto-layout, которое определяет Y
позицию, в данном случае это расстояние от нижней части суперпредставления, и изменяю константу:
- (void)moveBannerOffScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = -32;
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = 0;
}];
bannerIsVisible = TRUE;
}
И баннер движется именно так, как и ожидалось, но без анимации.
ОБНОВЛЕНИЕ: я повторно смотрел доклад WWDC 12 «Лучшие практики для освоения автоматической компоновки», который охватывает анимацию. Здесь обсуждается, как обновить ограничения с помощью CoreAnimation :
Я пытался с помощью следующего кода, но получить точно такие же результаты:
- (void)moveBannerOffScreen {
_addBannerDistanceFromBottomConstraint.constant = -32;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
_addBannerDistanceFromBottomConstraint.constant = 0;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = TRUE;
}
Кстати, я проверял множество раз, и это выполняется в главном потоке.
Ответы:
Два важных замечания:
Вам нужно позвонить
layoutIfNeeded
в блоке анимации. Apple фактически рекомендует вызывать его один раз перед блоком анимации, чтобы убедиться, что все ожидающие операции макета были завершеныВы должны вызывать его специально для родительского представления (например
self.view
), а не для дочернего представления, к которому прикреплены ограничения. Это обновит все ограниченные представления, включая анимацию других представлений, которые могут быть ограничены видом, для которого вы изменили ограничение (например, представление B прикреплено к нижней части представления A, и вы только что изменили верхнее смещение представления A, и вам нужно представление B). оживить с этим)Попробуй это:
Objective-C
Свифт 3
источник
setNeedsLayout
вместоlayoutIfNeeded
. Я немного испуган тем, сколько часов я провел, не замечая, что я просто набрал неправильное имя метода.Я ценю предоставленный ответ, но я думаю, что было бы неплохо пойти еще дальше.
Основной блок анимации из документации
но на самом деле это очень упрощенный сценарий. Что, если я хочу анимировать ограничения subview с помощью
updateConstraints
метода?Блок анимации, который вызывает метод updateConstraints для подпредставлений
Метод updateConstraints переопределяется в подклассе UIView и должен вызывать super в конце метода.
Руководство по AutoLayout оставляет желать лучшего, но его стоит прочитать. Я сам использую это как часть объекта,
UISwitch
который переключает подпредставление с паройUITextField
s с простой и тонкой анимацией коллапса (длиной 0,2 секунды). Ограничения для подпредставления обрабатываются в методах updateConstraints подклассов UIView, как описано выше.источник
self.view
(а не в подпредставлении этого представления), вызовupdateConstraintsIfNeeded
не требуется (посколькуsetNeedsLayout
также запускаютсяupdateConstraints
эти представления). Может быть, тривиально для большинства, но это было не для меня до сих пор;)Как правило, вам просто нужно обновить ограничения и вызвать
layoutIfNeeded
внутри блока анимации. Это может быть либо изменение.constant
свойстваNSLayoutConstraint
, добавление удаления ограничений (iOS 7), либо изменение.active
свойства ограничений (iOS 8 и 9).Образец кода:
Пример настройки:
полемика
Есть несколько вопросов о том, следует ли изменить ограничение перед блоком анимации или внутри него (см. Предыдущие ответы).
Ниже приведен разговор в Твиттере между Мартином Пилкингтоном, который преподает iOS, и Кеном Ферри, который написал Auto Layout. Кен объясняет, что хотя изменение констант за пределами блока анимации может в настоящее время работать, это небезопасно, и их действительно следует менять внутри блока анимации. https://twitter.com/kongtomorrow/status/440627401018466305
Анимация:
Пример проекта
Вот простой проект, показывающий, как можно анимировать вид. Он использует Objective C и анимирует представление, изменяя
.active
свойство нескольких ограничений. https://github.com/shepting/SampleAutoLayoutAnimationисточник
источник
Swift 4 решение
UIView.animate
Три простых шага:
Измените ограничения, например:
Скажите содержанию,
view
что его макет грязный и что autolayout должен пересчитать макет:В анимационном блоке укажите макету пересчитать макет, что эквивалентно установке кадров непосредственно (в этом случае autolayout установит кадры):
Завершите самый простой пример:
Примечание
Существует необязательный 0-й шаг - перед изменением ограничений вы можете захотеть вызвать,
self.view.layoutIfNeeded()
чтобы убедиться, что отправная точка для анимации находится в состоянии со примененными старыми ограничениями (в случае, если были некоторые другие изменения ограничений, которые не должны быть включены в анимацию) ):UIViewPropertyAnimator
Поскольку в iOS 10 появился новый механизм анимации -
UIViewPropertyAnimator
мы должны знать, что в основном к нему применяется тот же механизм. Шаги в основном одинаковы:Поскольку
animator
это инкапсуляция анимации, мы можем сохранить ссылку на нее и вызвать ее позже. Тем не менее, поскольку в анимационном блоке мы просто указываем автопутешествию пересчитывать кадры, нам нужно изменить ограничения перед вызовомstartAnimation
. Поэтому что-то подобное возможно:Порядок изменения ограничений и запуска аниматора важен - если мы просто изменим ограничения и оставим наш аниматор для более поздней точки, следующий цикл перерисовки может вызвать пересчет автоперестановки, и изменение не будет анимированным.
Кроме того, помните, что один аниматор не предназначен для повторного использования - как только вы запустите его, вы не сможете «перезапустить» его. Поэтому я думаю, что на самом деле нет веской причины держать аниматора рядом, если только мы не используем его для управления интерактивной анимацией.
источник
Раскадровка, код, советы и несколько ошибок
Другие ответы просто хороши, но этот выдвигает на первый план несколько довольно важных моментов анимации ограничений. Я прошел через множество вариаций, прежде чем понял следующее:
Установите ограничения, на которые вы хотите ориентироваться, в переменные класса, чтобы они содержали сильную ссылку. В Swift я использовал ленивые переменные:
После некоторого эксперимента я заметил, что один ДОЛЖЕН получить ограничение из представления НАД (или суперпредставление) двух представлений, где ограничение определено. В приведенном ниже примере (MNGStarRating и UIWebView - это два типа элементов, между которыми я создаю ограничение, и они являются подпредставлениями в self.view).
Цепочка фильтров
Я использую метод фильтра Свифта, чтобы отделить желаемое ограничение, которое будет служить точкой перегиба. Можно также сделать намного более сложным, но фильтр делает хорошую работу здесь.
Анимация ограничений с помощью Swift
Предполагая, что вы создаете свойство для фильтрации с точными критериями и получаете конкретную точку перегиба для вашей анимации (конечно, вы также можете фильтровать массив и проходить через него, если вам нужно несколько ограничений):
....
Немного позже...
Много неправильных поворотов
Эти заметки действительно набор советов, которые я написал для себя. Я сделал все, что не делал лично и мучительно. Надеюсь, это руководство может пощадить других.
Остерегайтесь zPosition. Иногда, когда ничего не происходит, вы должны скрыть некоторые другие виды или использовать отладчик, чтобы найти анимированный вид. Я даже обнаружил случаи, когда определяемый пользователем атрибут времени выполнения терялся в xml раскадровки и приводил к покрытию анимированного представления (во время работы).
Всегда уделяйте минуту чтению документации (новой и старой), быстрой справки и заголовков. Apple продолжает вносить множество изменений, чтобы лучше управлять ограничениями AutoLayout (см. Стековые представления). Или, по крайней мере, поваренная книга AutoLayout . Имейте в виду, что иногда лучшие решения находятся в старой документации / видео.
Поиграйте со значениями в анимации и рассмотрите возможность использования других вариантов animateWithDuration.
Не указывайте конкретные значения макета в качестве критерия для определения изменений других констант, вместо этого используйте значения, которые позволяют вам определить местоположение представления.
CGRectContainsRect
это один примерlet viewMargins = self.webview.layoutMarginsGuide
: это на примереБыстрый образец решений, чтобы избежать при использовании раскадровки
Если вы забудете один из этих или более простых советов, например, о том, где добавить layoutIfNeeded, скорее всего ничего не произойдет: в этом случае у вас может получиться полуобжаренное решение, подобное следующему:
Фрагмент из руководства AutoLayout (обратите внимание, что второй фрагмент предназначен для использования OS X). Кстати - это больше не в текущем руководстве, насколько я вижу. Предпочтительные методы продолжают развиваться.
Анимация изменений, сделанных автоматическим макетом
Если вам нужен полный контроль над анимацией изменений, сделанных в Auto Layout, вы должны внести свои ограничения программно. Основная концепция одинакова как для iOS, так и для OS X, но есть несколько незначительных отличий.
В приложении для iOS ваш код будет выглядеть примерно так:
В OS X используйте следующий код при использовании анимаций на основе слоев:
Когда вы не используете анимации на основе слоев, вы должны анимировать константу с помощью аниматора ограничения:
Для тех, кто учится лучше визуально, посмотрите это раннее видео от Apple .
Обратить особое внимание
Часто в документации есть небольшие заметки или фрагменты кода, которые приводят к большим идеям. Например, присоединение ограничений автоматического размещения к динамическим аниматорам - большая идея.
Удачи и да пребудет с тобой Сила.источник
Быстрое решение:
источник
Рабочий раствор 100% Swift 3.1
Я прочитал все ответы и хочу поделиться кодом и иерархией строк, которые я использовал во всех своих приложениях, чтобы правильно их анимировать. Некоторые решения здесь не работают, вы должны проверить их на более медленных устройствах, например, iPhone 5 в данный момент.
источник
Я пытался оживить ограничения, и мне было нелегко найти хорошее объяснение.
То, что говорят другие ответы, совершенно верно: вам нужно позвонить
[self.view layoutIfNeeded];
внутрьanimateWithDuration: animations:
. Однако, другой важный момент - иметь указатели для каждого, чтоNSLayoutConstraint
вы хотите оживить.Я создал пример в GitHub .
источник
Рабочее и только что протестированное решение для Swift 3 с Xcode 8.3.3:
Просто помните, что self.calendarViewHeight является ограничением, относящимся к customView (CalendarView). Я вызвал .layoutIfNeeded () для self.view, а НЕ для self.calendarView
Надеюсь, это поможет.
источник
Есть статья об этом: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was
В котором он закодирован так:
Надеюсь, поможет.
источник
В контексте анимации ограничений я хотел бы упомянуть конкретную ситуацию, в которой я анимировал ограничение непосредственно в уведомлении с клавиатуры.
Ограничение определило верхний пробел от текстового поля до вершины контейнера. При открытии клавиатуры я просто делю константу на 2.
Мне не удалось добиться последовательной плавной анимации ограничений непосредственно в уведомлении клавиатуры. Примерно в половине случаев изображение просто переместится на новую позицию - без анимации.
Мне пришло в голову, что в результате открытия клавиатуры может возникнуть дополнительная раскладка. Добавление простого блока dispatch_after с задержкой 10 мс заставляло анимацию запускаться каждый раз - без прыжков.
источник