【问题标题】:How to slide multiple UIViews with same speed如何以相同的速度滑动多个 UIView
【发布时间】:2021-05-28 19:08:07
【问题描述】:

我的故事板中有两个视图,我通过以下代码使用高度约束来滑动它们。

滑动后高度为 150.0 的 ViewOne

       UIView.animate(withDuration: 0.3) {
            self.con_ViewOneHeight.constant = 150.0
            self.view.layoutIfNeeded()
        }

滑动后高度为 1000.0 的 ViewTwo

       UIView.animate(withDuration: 0.3) {
            self.con_ViewTwoHeight.constant = 1000.0
            self.view.layoutIfNeeded()
        }

两个动画都在 0.3 秒内发生,但第二个视图的动画发生的速度比第一个快。我知道发生这种情况是因为时间相同,但我们如何计算每个具有相同速度的视图的时间?

【问题讨论】:

  • 您的问题有点令人困惑...两个视图的 starting 高度是否相同?那么,您希望它们以相同的“速度”调整大小,直到它们都达到 150 点,然后继续以相同的相对速度增长 ViewTwo,直到达到 1000 点?
  • @DonMag 两个视图的初始大小均为 0
  • 那么,我剩下的问题的答案是“是”吗?您希望它们都以相同的速度扩展直到达到 150 分,然后您希望 ViewTwo 以相同的速度继续扩展到 1000 分?
  • 从 0 开始我需要第一个 View 增长到 150,第二个 View 增长到 1000 以相同的速度

标签: ios swift animation uiview uikit


【解决方案1】:

为了简单起见,假设您希望 viewOne 从零变为 100,并且 viewTwo 高度从零变为 200...

如果将 viewOne 的动画持续时间设置为 1 秒,则 viewTwo 的持续时间需要为 2 秒。

所以,你可以这样做:

    // duration for viewOne animation
    let dur1 = 0.5
    // calculate needed duration for viewTwo animation
    let dur2 = (1000.0 / 150.0) * dur1

    UIView.animate(withDuration: dur1, delay: 0.0, options: [.curveLinear], animations: {
        self.con_ViewOneHeight.constant = 150.0
        self.view.layoutIfNeeded()
    }, completion: nil)
    
    UIView.animate(withDuration: dur2, delay: 0.0, options: [.curveLinear], animations: {
        self.con_ViewTwoHeight.constant = 1000.0
        self.view.layoutIfNeeded()
    }, completion: nil)

这是一个工作示例。点击视图中的任意位置以展开 viewOne(蓝色)和 viewTwo(红色)。每次点击都会重置并重新运行动画:

class DoubleGrowViewController: UIViewController {

    let viewOne = UIView()
    let viewTwo = UIView()
    
    var con_ViewOneHeight: NSLayoutConstraint!
    var con_ViewTwoHeight: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        viewOne.translatesAutoresizingMaskIntoConstraints = false
        viewTwo.translatesAutoresizingMaskIntoConstraints = false
        
        viewOne.backgroundColor = .blue
        viewTwo.backgroundColor = .red
        
        view.addSubview(viewOne)
        view.addSubview(viewTwo)
        
        con_ViewOneHeight = viewOne.heightAnchor.constraint(equalToConstant: 0.0)
        con_ViewTwoHeight = viewTwo.heightAnchor.constraint(equalToConstant: 0.0)
        
        // respect safe-area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            viewOne.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            viewOne.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            viewOne.widthAnchor.constraint(equalToConstant: 150.0),
            
            con_ViewOneHeight,
            
            viewTwo.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            viewTwo.leadingAnchor.constraint(equalTo: viewOne.trailingAnchor, constant: 20.0),
            viewTwo.widthAnchor.constraint(equalToConstant: 150.0),
            
            con_ViewTwoHeight,
            
        ])

        let t = UITapGestureRecognizer(target: self, action: #selector(self.doAnim(_:)))
        view.addGestureRecognizer(t)
        
    }
    
    @objc func doAnim(_ g: UITapGestureRecognizer?) -> Void {

        // if the animation is running, we'll
        //  stop it
        //  reset view height constraints to 0
        //  re-start the animation (async)
        if con_ViewOneHeight.constant != 0.0 {
            viewOne.layer.removeAllAnimations()
            viewTwo.layer.removeAllAnimations()
            con_ViewOneHeight.constant = 0.0
            con_ViewTwoHeight.constant = 0.0
            DispatchQueue.main.async {
                self.doAnim(nil)
            }
            return
        }
        
        // duration for viewOne animation
        let dur1 = 0.5
        // calculate needed duration for viewTwo animation
        let dur2 = (1000.0 / 150.0) * dur1

        UIView.animate(withDuration: dur1, delay: 0.0, options: [.curveLinear], animations: {
            self.con_ViewOneHeight.constant = 150.0
            self.view.layoutIfNeeded()
        }, completion: nil)
        
        UIView.animate(withDuration: dur2, delay: 0.0, options: [.curveLinear], animations: {
            self.con_ViewTwoHeight.constant = 1000.0
            self.view.layoutIfNeeded()
        }, completion: nil)

    }
    
}

【讨论】:

    【解决方案2】:

    您应该以秒/点为单位设置所需的速度,然后计算每个高度的时间:

    let speed = 0.3/150.0 // 0.3 seconds for 150 points
    let heightForViewOne = 150.0 
    let timeForViewOne = heightForViewOne * speed // (=0.3s)
    let heightForViewTwo = 1000.0
    let timeForViewTwo = heightForViewTwo * speed // (=2s)
    

    然后在动画调用中使用timeForViewxxx和heightForViewxxx

    【讨论】:

    • 我已经尝试过了,但结果速度变得比第一个视图慢了很多
    • 您可以尝试使用每个视图的前后高度之间的差异吗?即abs(heightAfterOne-heightBeforeOne)
    猜你喜欢
    • 1970-01-01
    • 2012-02-04
    • 2020-01-13
    • 2013-09-19
    • 1970-01-01
    • 2017-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多