2017-02-24 92 views
2

加入後,我有我編程方式添加到我的UIViewController像這樣的的UIView:動畫的UIView與約束它編程

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

但是,什麼是正確的,現在,從屏幕頂部滑動到屏幕的centerY以及在它會調整到的邊緣,同時做左,右像它在第一約束集

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

我完全困惑,現在我希望我的解釋有幫助,有人有一個想法。

謝謝!

+0

爲什麼程序化與IBOutlet有關係?無論您想要如何設置您的預動畫約束,然後設置您的後動畫約束,然後在需要更改時在動畫塊內調用「layoutIfNeeded」。 – Connor

回答

1

由於我不知道你的觀點是從你的包創建的,我已經根據您的代碼入侵了一個快速示例。

關鍵是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!) 
    } 
} 
+0

謝謝!確實問題是我不得不兩次調用layoutIfNeeded。將視圖添加到控制器後,然後添加到動畫塊中。 今天學到了東西,謝謝! –

1

創建約束並將其保存在實例變量中。然後當你想動畫時,改變約束上的常量並從動畫塊中調用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() 
    }) 
+0

謝謝,是的,你說的對,昨天已經晚了。 事實上,我可以將約束存儲在一個變量中。 但我仍然有問題。我必須添加多個評論,否則我沒有足夠的角色來解釋,對不起。 –

+0

我把我的約束像 yConstraint = NSLayoutConstraint(項目:MyView的, 屬性:.centerY, relatedBy:.equal, toItem:self.view, 屬性:.centerY, 乘數:1, 常數:CGFloat的( !UIScreen.main.bounds.height)) self.view.addConstraint(yConstraint) –

+0

和更新一樣 UIView.animate(withDuration:1.0, 動畫: { self.yConstraint .constant = CGFloat的(0.0) () }) 但是,它從頂部滑入,爲什麼?並不是獨一無二的,它還可以調整我設置的第一個約束的左右邊界的大小(您可以在第一個帖子中看到它,即將頁邊距保持在左右的那個)。 我很抱歉,我越想越感到困惑。 在myView上調用layoutIfNeeded而不是self.view不起作用,它只從左右調整 –