Потяните вверх и опустите UIView с изменением положения x
редактировать
Это то, что я хочу визуализировать (игнорируйте уродливую красную линию, это просто указывает на движение UIView):
Я хочу иметь UIView, который инициализируется в середине экрана. После этого я хочу подтолкнуть его вверх, и гравитация потянет его вниз, пока он не исчезнет с экрана. Мой старый вопрос работает с UIPushBehaviour, UIDynamicBehaviour и UIGravityBehaviour (см. Ниже). Мэтт отметил, что UIPushBehaviour, возможно, не правильный выбор, так как он не очень хорошо работает на всех экранах, доступных в iOS.
Я могу сделать это с помощью функции UIView.animate, но она действительно статична и не выглядит естественной. С UIPushBehaviour, UIDynamicBehaviour и UIGravityBehaviour это выглядит действительно хорошо, но величина UIPushBehaviour не может быть рассчитана для каждого размера экрана, чтобы дать одинаковую конечную точку положения x и y UIView.
Вопрос
Как я могу инициализировать UIView в середине экрана, "поднять" этот UIView (с некоторым изменением положения x) и позволить гравитации (или что-то еще) потянуть его вниз, пока он не исчезнет с экрана? Важно, чтобы изменение положения x и y было одинаковым для каждого размера экрана.
Ниже мой старый вопрос
у меня есть UIPushBehaviour
с instantaneous
как режим, в котором я нажимаю некоторые UIView
вокруг. Чем больше размер экрана, тем меньше он толкает.
у меня тоже есть UIDynamicItemBehavior
с resistance
установлен в 1
Я думаю, что это одна из основных причин, по которой он отличается в зависимости от размера экрана (поправьте меня, если я ошибаюсь).
Я хочу функцию, которая будет толкать UIView
до одной и той же конечной точки с одинаковой скоростью, продолжительностью и конечной точкой независимо от размера экрана.
Я попытался сделать относительную величину без удачи:
Для iPhone 5S, скажем, magnitude
из 0.5
коснется UIView
от середины к вершине. Я хотел рассчитать величину на всех устройствах, как это:
let y = 0.5 / 520 // 5S screen height
magnitude = self.view.frame.height * y
Для iPhone 8 у него совсем другой выход и он не работает. Читая документы, я думал, что пойму это. Я думал, что 1 величина представляет 100 пикселей, но это явно не тот случай.
Есть ли способ, которым я могу вычислить величину, например, чтобы переместить UIView
с середины на право?
Я сделал проект здесь. Есть черный UIView
на iPhone 5 это все дошло до краев, но не на iPhone 8.
1 ответ
Решение
Вам нужно масштабировать величину толчка относительно размера экрана, чтобы ваш обзор всегда заканчивался в одном и том же месте. Для этого нужно настроить UIPushBehavior
"s pushDirection
вектор работает довольно хорошо. В этом случае я установил направление нажатия пропорционально границам вида и уменьшил его на постоянный коэффициент.
let push = UIPushBehavior(items: [pushView], mode: .instantaneous)
let pushFactor: CGFloat = 0.01
push.pushDirection = CGVector(dx: -view.bounds.width * pushFactor, dy: -view.bounds.height * pushFactor)
animator.addBehavior(push)
Возможно, вам придется настроить некоторые константы, чтобы получить именно ту анимацию, которую вы хотите. Константы, которые вы можете настроить:
- Сила тяжести (в настоящее время 0,3)
- Фактор толчка (в настоящее время 0,01)
В зависимости от ваших потребностей, вам может понадобиться масштабировать величину гравитации, пропорциональную размеру экрана.
Примечание. Эти константы необходимо будет изменять в зависимости от размера анимированного представления, поскольку UIKit Dynamics рассматривает размер представления как его массу. Если ваш вид должен иметь динамический размер, вам нужно масштабировать ваши константы в соответствии с размером анимированного представления.
Изменить в отношении комментариев на оригинальный вопрос:
Представления разных размеров. Как я уже упоминал в моей заметке выше, вам необходимо применить дополнительный фактор для учета "массы" представлений. Что-то вроде
view.frame.height * view.frame.width * someConstant
должно хорошо работать.Размер экрана iPad: в настоящее время
pushFactor
применяется как кdx
а такжеdy
компоненты вектора. Поскольку у iPad разные пропорции, вам нужно разделить их на две константы, может бытьxPushFactor
а такжеyPushFactor
, что может объяснить различия в соотношении сторон.
Примеры
iPhone 8
iPhone SE
Полный исходный код детской площадки
Скопируйте и вставьте этот код в игровую площадку Swift, чтобы увидеть его в действии. Я включил размеры различных экранов iPhone, поэтому просто раскомментируйте размер, который вы хотите легко протестировать на разных устройствах. Большая часть интересного / релевантного кода находится в viewDidAppear
,
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let pushView = UIView()
var animator: UIDynamicAnimator!
override func viewDidLoad() {
super.viewDidLoad()
view.frame = CGRect(x: 0, y: 0, width: 568, height: 320) // iPhone SE
// view.frame = CGRect(x: 0, y: 0, width: 667, height: 375) // iPhone 8
// view.frame = CGRect(x: 0, y: 0, width: 736, height: 414) // iPhone 8+
// view.frame = CGRect(x: 0, y: 0, width: 812, height: 375) // iPhone X
view.backgroundColor = .white
let pushViewSize = CGSize(width: 200, height: 150)
pushView.frame = CGRect(x: view.bounds.midX - pushViewSize.width / 2, y: view.bounds.midY - pushViewSize.height / 2, width: pushViewSize.width, height: pushViewSize.height)
pushView.backgroundColor = .red
view.addSubview(pushView)
animator = UIDynamicAnimator(referenceView: self.view)
let dynamic = UIDynamicItemBehavior()
dynamic.resistance = 1
animator.addBehavior(dynamic)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let gravity = UIGravityBehavior(items: [pushView])
gravity.magnitude = 0.3
animator.addBehavior(gravity)
let push = UIPushBehavior(items: [pushView], mode: .instantaneous)
let pushFactor: CGFloat = 0.01
push.pushDirection = CGVector(dx: -view.bounds.width * pushFactor, dy: -view.bounds.height * pushFactor)
animator.addBehavior(push)
}
}
let vc = ViewController()
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = vc.view