簡體   English   中英

以編程方式添加后,使用約束動畫UIView

[英]Animate UIView with constraints after it was added programmatically

我有一個UIView,我以編程方式添加到我的UIViewController,如下所示:

if let myView = Bundle.main.loadNibNamed("MyView", owner: self, options: nil)?.first as? MyView
    {
        self.view.addSubview(myView)
        myView.translatesAutoresizingMaskIntoConstraints = false
        //Horizontal orientation
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":myView]))
    }

多數民眾贊成,視圖在視圖控制器的(0,0)左右兩側添加了所需的空間。

我想要實現的是視圖從視圖控制器的底部動畫到中心,然后從中心到頂部進行動畫制作。 首先,我試圖將它設置為動畫,使其從當前位置(0,0)開始居中

所以我做的是:

UIView.animate(withDuration: 1.0,
                   animations:
    {
        let center = NSLayoutConstraint(item: myView, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: CGFloat(0.0))
        self.view.addConstraint(center)
    })

那么視圖位於中心,但它不是動畫。 它直接跳到它。

我搜索並找到了很多答案,說我必須設置約束的常量,然后調用layoutIfNeeded()但所有這些示例都使用對之前設置為IBOutlet的約束的引用,我沒有添加我的以編程方式查看。

如何正確地為視圖設置動畫,從底部到中心然后從中心到頂部?

謝謝你!

問候

編輯1

好的,我會更進一步解釋我想要實現的目標。 在我的視圖控制器上,在向用戶顯示5秒計時器后,我想一個接一個地顯示幾個問題。

我想要一個問題從下到中滑入,已經回答,然后從中心向上滑動。 然后下一個問題從下到中,從幻燈片中取出,等等。

因此,在5秒計時器之后,我調用名為slideInQuestion的方法創建一個問題,並將其設置為動畫:

func slideInQuestion()
{
    let question:QuestionView = createQuestion()
    UIView.animate(withDuration: 1.0,
                   animations:
    {
        self.yConstraint?.constant = CGFloat(0.0)
        self.view.layoutIfNeeded()
    })

createQuestion方法實例化問題視圖並為其分配約束

func createQuestion() -> QuestionView
{
    if let questionView = Bundle.main.loadNibNamed("QuestionView", owner: self, options: nil)?.first as? QuestionView
    {
        self.view.addSubview(questionView)
        questionView.translatesAutoresizingMaskIntoConstraints = false
        //Horizontal orientation
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":questionView]))
        yConstraint = NSLayoutConstraint(item: questionView,
                                              attribute: .centerY,
                                              relatedBy: .equal,
                                              toItem: self.view,
                                              attribute: .centerY,
                                              multiplier: 1,
                                              constant: CGFloat(UIScreen.main.bounds.height))
        self.view.addConstraint(yConstraint!)
        return questionView
    }
    return QuestionView()
}

在此之前,我將yConstraint定義為Duncan C建議的實例變量,如下所示:

    var yConstraint:NSLayoutConstraint?

所以我對現在的期望是:

創建問題視圖,它的中心位於視圖控制器的中心+屏幕的高度。 這使它在屏幕底部的可見視圖之外。 然后它在1秒內從該位置滑動到屏幕的中心Y(0.0)。

但它現在做的是,從屏幕頂部滑動到屏幕的中心Y,同時它調整到左右邊距,就像它在第一個約束中設置一樣

self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":questionView]))

我現在完全糊塗了,希望我的解釋有所幫助,有人有個主意。

謝謝!

由於我不知道您的視圖是如何從您的軟件包中創建的,因此我根據您的代碼將一個快速示例混合在一起。

關鍵是self.view.layoutIfNeeded()被調用兩次。 一旦添加了視圖,第二次在動畫塊中。 並且約束的修改不在動畫塊內。

import UIKit

class ViewController: UIViewController {

    var yConstraint:NSLayoutConstraint?

    override func viewWillAppear(_ animated: Bool) {

        self.createView()

        self.view.layoutIfNeeded()

        self.yConstraint?.constant = 32
        UIView.animate(withDuration: 1.0) {
            self.view.layoutIfNeeded()
        }

    }

    func createView(){

        let questionView = UIView()
        questionView.backgroundColor = UIColor.red

        let heightConstraint = NSLayoutConstraint(item: questionView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: self.view.bounds.height-64)
        questionView.addConstraint(heightConstraint)

        self.view.addSubview(questionView)

        questionView.translatesAutoresizingMaskIntoConstraints = false

        //Horizontal orientation
        self.view.addConstraints(
            NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":questionView]))

        yConstraint = NSLayoutConstraint(item: questionView,
                                         attribute: .top,
                                         relatedBy: .equal,
                                         toItem: self.view,
                                         attribute: .top,
                                         multiplier: 1,
                                         constant: CGFloat(UIScreen.main.bounds.height))
        self.view.addConstraint(yConstraint!)
    }
}

創建約束並將其保存在實例變量中。 然后,當您想要為其設置動畫時,更改約束上的常量並從動畫塊調用layoutIfNeeded,就像為動畫基於故事板的約束設置動畫一樣。

在你的情況下,不要在你的函數中使用let constraint = ... 相反,使用:

var centerConstraint: NSLayoutConstraint?

在viewWillAppear中:

centerConstraint = NSLayoutConstraint(item: myView, 
  attribute: .centerY, 
  relatedBy: .equal, 
  toItem: self.view, 
  attribute: .centerY,  
  multiplier: 1,  
  constant: CGFloat(0.0))
self.view.addConstraint(center)

當你想要動畫時:

UIView.animate(withDuration: 1.0,
                   animations:
    {
       centerConstraint.constant = newValue  //(Your value here.)
       myView.layoutIfNeeded()
    })

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM