【问题标题】:How to properly transform UIView's scale on UIScrollView movement如何在 UIScrollView 移动时正确转换 UIView 的比例
【发布时间】:2017-04-18 10:11:23
【问题描述】:

为了产生与 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) 消除了问题。 UIView 对象的滚动以及Y-movement 再次平滑。

转换对象比例的最佳方法是什么?

没有布局约束。

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)
}

【问题讨论】:

  • 你的按钮有透明背景吗?如果是这样,您可以将其关闭并重试吗?您也可以在制作动画时尝试button.layer.shouldRasterize = true
  • 按钮没有颜色。只是一个 UIImage(带有透明元素的 pdf)
  • 从您的 gif 中,尝试将背景设置为黑色。
  • layer.shouldRasterize = true = 仍然滞后。让我检查 BG。秒
  • backgroundColor = .black = 仍然滞后

标签: swift uiview uiscrollview


【解决方案1】:

发生这种情况是因为您同时应用了:transformframe。如果您只申请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))

    }
}

【讨论】:

  • 好吧。该公式不再适用于这种方法。但过渡是平稳的。只需要调整公式。认为这将是我要走的路。谢谢你的帮助
【解决方案2】:

您可以通过创建动画然后将图层的速度设置为 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/

【讨论】:

  • 您的方法也很有效。但另一个答案更容易,并且更接近我的方法。但我会拭目以待,看看还有哪些其他选择。赏金期结束后,无论哪种方式,您都将获得当之无愧的支持!非常感谢您的努力
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2011-08-01
相关资源
最近更新 更多