为了对Snapchat的HUD运动产生类似的效果,我根据UIScollView's
contentOffset
创建了HUD元素的移动。 修改:Link to the Github project 。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.view.layoutIfNeeded()
let factor = scrollView.contentOffset.y / self.view.frame.height
self.transformElements(self.playButton,
0.45 + 0.55 * factor, // 0.45 = desired scale + 0.55 = 1.0 == original scale
Roots.screenSize.height - 280, // 280 == original Y
Roots.screenSize.height - 84, // 84 == minimum desired Y
factor)
}
func transformElements(_ element: UIView?,
_ scale: CGFloat,
_ originY: CGFloat,
_ desiredY: CGFloat,
_ factor: CGFloat) {
if let e = element {
e.transform = CGAffineTransform(scaleX: scale, y: scale) // this line lagging
let resultY = desiredY + (originY - desiredY) * factor
var frame = e.frame
frame.origin.y = resultY
e.frame = frame
}
}
实现此代码后,滚动和转换似乎是"滞后" /不平滑。 (物理iPhone 6S +和7 +)。
删除以下行:e.transform = CGAffineTransform(scaleX: scale, y: scale)
删除了该问题。滚动以及Y-movement
对象的UIView
再次平滑。
改变对象规模的最佳方法是什么?
没有布局约束。
func setupPlayButton() {
let rect = CGRect(x: Roots.screenSize.width / 2 - 60,
y: Roots.screenSize.height - 280,
width: 120,
height: 120)
self.playButton = UIButton(frame: rect)
self.playButton.setImage(UIImage(named: "playBtn")?.withRenderingMode(.alwaysTemplate), for: .normal)
self.playButton.tintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
self.view.addSubview(playButton)
}
答案 0 :(得分:1)
通过创建动画然后将图层的速度设置为0,然后更改图层的timeOffset,可以使这些类型的动画更流畅。
首先在setupPlayButton
方法
let animation = CABasicAnimation.init(keyPath: "transform.scale")
animation.fromValue = 1.0
animation.toValue = 0.45
animation.duration = 1.0
//Set the speed of the layer to 0 so it doesn't animate until we tell it to
self.playButton.layer.speed = 0.0;
self.playButton.layer.add(animation, forKey: "transform");
下一个scrollViewDidScroll
更改图层的timeOffset并移动按钮的中心。
if let btn = self.playButton{
var factor:CGFloat = 1.0
if isVertically {
factor = scrollView.contentOffset.y / self.view.frame.height
} else {
factor = scrollView.contentOffset.x / Roots.screenSize.width
var transformedFractionalPage: CGFloat = 0
if factor > 1 {
transformedFractionalPage = 2 - factor
} else {
transformedFractionalPage = factor
}
factor = transformedFractionalPage;
}
//This will change the size
let timeOffset = CFTimeInterval(1-factor)
btn.layer.timeOffset = timeOffset
//now change the positions. only use center - not frame - so you don't mess up the animation. These numbers aren't right I don't know why
let desiredY = Roots.screenSize.height - (280-60);
let originY = Roots.screenSize.height - (84-60);
let resultY = desiredY + (originY - desiredY) * (1-factor)
btn.center = CGPoint.init(x: btn.center.x, y: resultY);
}
我无法完全按下按钮的位置 - 所以我的数学有问题,但我相信你可以解决它。
如果您想了解有关此技术的更多信息,请参阅此处:http://ronnqvi.st/controlling-animation-timing/
答案 1 :(得分:1)
这种情况正在发生,因为您同时应用了transform
和frame
。如果您仅应用transform
,它会更顺畅。更新您的transformElements
功能,如下所示:
func transformElements(_ element: UIView?,
_ scale: CGFloat,
_ originY: CGFloat,
_ desiredY: CGFloat,
_ factor: CGFloat) {
if let e = element {
e.transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: 0, y: desiredY * (1 - factor))
}
}