タップしたときの幅を拡大したいUITextFieldがあります。私は拘束を設定し、左側の拘束が右側でアニメートしようとしているものよりも低い優先順位を持つようにしました。
これが私が使おうとしているコードです。
// move the input box
UIView.animateWithDuration(10.5, animations: {
self.nameInputConstraint.constant = 8
}, completion: {
(value: Bool) in
println(">>> move const")
})
これはうまくいきますが、それはただちに起こるようであり、動きはないようです。私は私が何かを見逃していないことを確認するためにそれを10秒に設定しようとしました、しかし私は同じ結果を得ました。
nameInputConstraintは、IBから自分のクラスに接続するためにドラッグした制約の名前です。
事前にご協力いただきありがとうございます。
最初に制約を変更してから更新をアニメートする必要があります。
self.nameInputConstraint.constant = 8
UIView.animateWithDuration(0.5) {
self.view.layoutIfNeeded()
}
そしてSwift 3.0では:
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
Swift 4.x:
self.mConstraint.constant = 100.0
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
完成した例:
self.mConstraint.constant = 100
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
}, completion: {res in
//Do something
})
view.layoutIfNeeded()
はビューのサブビューにのみ適用されることを指摘することは非常に重要です。
したがって、ビューの制約をアニメートするには、次のようにview-to-animate superviewでそれを呼び出すことが重要です。
topConstraint.constant = heightShift
UIView.animate(withDuration: 0.3) {
// request layout on the *superview*
self.view.superview?.layoutIfNeeded()
}
次のような単純なレイアウトの例
class MyClass {
/// Container view
let container = UIView()
/// View attached to container
let view = UIView()
/// Top constraint to animate
var topConstraint = NSLayoutConstraint()
/// Create the UI hierarchy and constraints
func createUI() {
container.addSubview(view)
// Create the top constraint
topConstraint = view.topAnchor.constraint(equalTo: container.topAnchor, constant: 0)
view.translatesAutoresizingMaskIntoConstraints = false
// Activate constaint(s)
NSLayoutConstraint.activate([
topConstraint,
])
}
/// Update view constraint with animation
func updateConstraint(heightShift: CGFloat) {
topConstraint.constant = heightShift
UIView.animate(withDuration: 0.3) {
// request layout on the *superview*
self.view.superview?.layoutIfNeeded()
}
}
}
Swift 4.1とiOS 11では、あなたのニーズに応じて、あなたはあなたの問題を解決するために以下の3つの方法のうちの一つを選択することができます。
UIView
のanimate(withDuration:animations:)
クラスメソッドを使うanimate(withDuration:animations:)
は次のように宣言されています。
指定された期間を使用して、1つ以上のビューに対する変更をアニメートします。
class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void)
以下のPlaygroundコードは、自動レイアウト制約の定数の変化をアニメートするためのanimate(withDuration:animations:)
の可能な実装を示しています。
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let textView = UITextView()
lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(textView)
textView.backgroundColor = .orange
textView.isEditable = false
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.translatesAutoresizingMaskIntoConstraints = false
textView.topAnchor.constraintEqualToSystemSpacingBelow(view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
heightConstraint.isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
textView.addGestureRecognizer(tapGesture)
}
@objc func doIt(_ sender: UITapGestureRecognizer) {
heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
UIView.animate(withDuration: 2) {
self.view.layoutIfNeeded()
}
}
}
PlaygroundPage.current.liveView = ViewController()
UIViewPropertyAnimator
のinit(duration:curve:animations:)
イニシャライザとstartAnimation()
メソッドの使用init(duration:curve:animations:)
は次のように宣言されています。
組み込みのUIKitタイミングカーブでアニメーターを初期化します。
convenience init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> Void)? = nil)
以下のPlaygroundコードは、自動レイアウト制約の定数変更をアニメートするためのinit(duration:curve:animations:)
およびstartAnimation()
の可能な実装を示しています。
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let textView = UITextView()
lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(textView)
textView.backgroundColor = .orange
textView.isEditable = false
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.translatesAutoresizingMaskIntoConstraints = false
textView.topAnchor.constraintEqualToSystemSpacingBelow(view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
heightConstraint.isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
textView.addGestureRecognizer(tapGesture)
}
@objc func doIt(_ sender: UITapGestureRecognizer) {
heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: {
self.view.layoutIfNeeded()
})
animator.startAnimation()
}
}
PlaygroundPage.current.liveView = ViewController()
UIViewPropertyAnimator
のrunningPropertyAnimator(withDuration:delay:options:animations:completion:)
クラスメソッドを使うrunningPropertyAnimator(withDuration:delay:options:animations:completion:)
は次のように宣言されています。
アニメーションの実行をすぐに開始するアニメーターオブジェクトを作成して返します。
class func runningPropertyAnimator(withDuration duration: TimeInterval, delay: TimeInterval, options: UIViewAnimationOptions = [], animations: @escaping () -> Void, completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self
以下のPlaygroundコードは、自動レイアウト制約の定数の変化をアニメートするためのrunningPropertyAnimator(withDuration:delay:options:animations:completion:)
の可能な実装を示しています。
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let textView = UITextView()
lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(textView)
textView.backgroundColor = .orange
textView.isEditable = false
textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
textView.translatesAutoresizingMaskIntoConstraints = false
textView.topAnchor.constraintEqualToSystemSpacingBelow(view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
heightConstraint.isActive = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
textView.addGestureRecognizer(tapGesture)
}
@objc func doIt(_ sender: UITapGestureRecognizer) {
heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2, delay: 0, options: [], animations: {
self.view.layoutIfNeeded()
})
}
}
PlaygroundPage.current.liveView = ViewController()
私の場合は、カスタムビューのみを更新しました。
// DO NOT LIKE THIS
customView.layoutIfNeeded() // Change to view.layoutIfNeeded()
UIView.animate(withDuration: 0.5) {
customViewConstraint.constant = 100.0
customView.layoutIfNeeded() // Change to view.layoutIfNeeded()
}