UILabel 大小更改不会使用自动布局设置动画
UILabel size change doesn't animate with auto layout
我有一个动态宽度 UILabel
(颜色为石灰绿色以提高可见性),它对其邻居(绿色和红色视图)有固定的前导和尾随约束。我希望此 table 在其邻居之一移动时调整其宽度(圆形 red/green 视图)。但是,由于我的标签 "jumps" 的宽度在没有动画的情况下变为新值,因此我对这种变化的动画有疑问。对于我的右对齐标签,这意味着文本本身也会跳转。
我正在为 red/green 视图的移动设置动画,如下所示:
- (void)show {
self.edgeConstraint.constant = 0;
[UIView animateWithDuration:0.25 animations:^{
[self.contentView layoutIfNeeded];
}];
}
- (void)hide {
self.edgeConstraint.constant = -100;
[UIView animateWithDuration:0.25 animations:^{
[self.contentView layoutIfNeeded];
}];
}
问题出在 UILabel
内容模式上。您会看到类似的问题 here。因为您正在缩短绘制文本的标签,所以标签会执行绘制过程,但它会使用动画块的最后一帧进行更新。创建平滑动画的最简单方法是使用 greaterThanOrEqualTo
前导约束并将 textAlignment
设置为 .natural
。
当我这样做时,我得到的结果在顶部,而不是在底部设置 textAlignment
.right
。
演示源代码:
import UIKit
import PlaygroundSupport
final class ViewController: UIViewController {
var constraint: NSLayoutConstraint?
var otherConstraint: NSLayoutConstraint?
lazy private var sideView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(view)
view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.constraint = view.leadingAnchor.constraint(equalTo: self.view.trailingAnchor)
self.constraint?.isActive = true
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 44).isActive = true
view.backgroundColor = .yellow
return view
}()
lazy private var secondSideView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(view)
view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 44.0).isActive = true
self.otherConstraint = view.leadingAnchor.constraint(equalTo: self.view.trailingAnchor)
self.otherConstraint?.isActive = true
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 44).isActive = true
view.backgroundColor = .yellow
return view
}()
lazy private var label: UILabel = {
let label = UILabel()
label.text = "Label"
label.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(label)
label.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
label.leadingAnchor.constraint(greaterThanOrEqualTo: self.view.leadingAnchor, constant: 8.0).isActive = true
label.trailingAnchor.constraint(equalTo: self.sideView.leadingAnchor).isActive = true
return label
}()
lazy private var secondLabel: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.text = "Label"
label.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(label)
label.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 44.0).isActive = true
label.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 8.0).isActive = true
label.trailingAnchor.constraint(equalTo: self.sideView.leadingAnchor).isActive = true
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
self.secondSideView.isHidden = false
self.secondLabel.isHidden = false
self.sideView.isHidden = false
self.label.isHidden = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.perform(#selector(self.showSideView), with: nil, afterDelay: 5.0)
}
@objc private func showSideView() {
self.view.layoutIfNeeded()
UIView.animate(withDuration: 1.5, delay: 0.0, options: [.autoreverse, .repeat], animations: {
self.otherConstraint?.constant = -100
self.constraint?.constant = -100
self.view.layoutIfNeeded()
})
}
}
PlaygroundPage.current.liveView = ViewController()
我有一个动态宽度 UILabel
(颜色为石灰绿色以提高可见性),它对其邻居(绿色和红色视图)有固定的前导和尾随约束。我希望此 table 在其邻居之一移动时调整其宽度(圆形 red/green 视图)。但是,由于我的标签 "jumps" 的宽度在没有动画的情况下变为新值,因此我对这种变化的动画有疑问。对于我的右对齐标签,这意味着文本本身也会跳转。
我正在为 red/green 视图的移动设置动画,如下所示:
- (void)show {
self.edgeConstraint.constant = 0;
[UIView animateWithDuration:0.25 animations:^{
[self.contentView layoutIfNeeded];
}];
}
- (void)hide {
self.edgeConstraint.constant = -100;
[UIView animateWithDuration:0.25 animations:^{
[self.contentView layoutIfNeeded];
}];
}
问题出在 UILabel
内容模式上。您会看到类似的问题 here。因为您正在缩短绘制文本的标签,所以标签会执行绘制过程,但它会使用动画块的最后一帧进行更新。创建平滑动画的最简单方法是使用 greaterThanOrEqualTo
前导约束并将 textAlignment
设置为 .natural
。
当我这样做时,我得到的结果在顶部,而不是在底部设置 textAlignment
.right
。
演示源代码:
import UIKit
import PlaygroundSupport
final class ViewController: UIViewController {
var constraint: NSLayoutConstraint?
var otherConstraint: NSLayoutConstraint?
lazy private var sideView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(view)
view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.constraint = view.leadingAnchor.constraint(equalTo: self.view.trailingAnchor)
self.constraint?.isActive = true
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 44).isActive = true
view.backgroundColor = .yellow
return view
}()
lazy private var secondSideView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(view)
view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 44.0).isActive = true
self.otherConstraint = view.leadingAnchor.constraint(equalTo: self.view.trailingAnchor)
self.otherConstraint?.isActive = true
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 44).isActive = true
view.backgroundColor = .yellow
return view
}()
lazy private var label: UILabel = {
let label = UILabel()
label.text = "Label"
label.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(label)
label.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
label.leadingAnchor.constraint(greaterThanOrEqualTo: self.view.leadingAnchor, constant: 8.0).isActive = true
label.trailingAnchor.constraint(equalTo: self.sideView.leadingAnchor).isActive = true
return label
}()
lazy private var secondLabel: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.text = "Label"
label.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(label)
label.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 44.0).isActive = true
label.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 8.0).isActive = true
label.trailingAnchor.constraint(equalTo: self.sideView.leadingAnchor).isActive = true
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
self.secondSideView.isHidden = false
self.secondLabel.isHidden = false
self.sideView.isHidden = false
self.label.isHidden = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.perform(#selector(self.showSideView), with: nil, afterDelay: 5.0)
}
@objc private func showSideView() {
self.view.layoutIfNeeded()
UIView.animate(withDuration: 1.5, delay: 0.0, options: [.autoreverse, .repeat], animations: {
self.otherConstraint?.constant = -100
self.constraint?.constant = -100
self.view.layoutIfNeeded()
})
}
}
PlaygroundPage.current.liveView = ViewController()