我的UITableView
的左侧是UIView
,右边是普通的UIViewController
UITableView
连接到其中的.top
,.leading
和.bottom
superview
UIView
连接到其中的.top
,.trailing
和.bottom
superview
,也有.width
UITableView
.leading
==
.trailing
中的UIView
您可以在屏幕截图上看到所有这些限制:
这是我在控制器中的动画代码,如您所见,我更新了.width
的{{1}}并循环播放了动画。
UIView
因此,您可以在.gif上看到此内容,我应该如何进行平滑动画处理而又不出现毛刺?
答案 0 :(得分:4)
更新
我尝试使用自己的UILabel
子类重现UIView
的错误行为:
class MyView: UIView {
var currentSize: CGSize = .zero
override func layoutSubviews() {
super.layoutSubviews()
guard currentSize != bounds.size else { return }
currentSize = bounds.size
setNeedsDisplay()
}
override func draw(_ rect: CGRect) {
UIColor.purple.setFill()
UIBezierPath(rect: rect).fill()
let square = CGRect(x: rect.width - 50, y: rect.origin.y, width: 50, height: rect.height)
UIColor.blue.setFill()
UIBezierPath(rect: square).fill()
}
}
该视图在其右侧绘制一个蓝色的小矩形作为文本。而且……嗯……动画也不错!
但是如果我将contentMode
更改为left
(默认值为scaleToFill
)
蓝色方块从一个地方跳到另一个地方。
因此,我发现这不仅与UILabel
的{{1}}有关。它与textAlignment
的默认left
内容模式结合在一起。
UILabel
定义了在内容大小和边界大小不同的情况下应如何调整内容-在动画制作中就是这种情况,在调整大小之前,视图会以新的大小重新绘制自己。
所以
contentMode
将表现为:
label.contentMode = .left // default
label.textAlignment = .left
上级答案
我花了一些时间解决您的问题。你猜怎么了?
它与表格视图完全无关。这是因为标签的label.contentMode = .right
label.textAlignment = .right
文本对齐。
您可以使用简单的.right
重现故障:
UILabel
为什么?
要找出错误,我创建了一个class ViewController: UIViewController {
let label = UILabel()
var rightConstraint: NSLayoutConstraint!
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
start()
}
func start() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
if self.rightConstraint.constant == 50 {
self.change(width: 100)
} else {
self.change(width: 50)
}
self.start()
}
}
func change(width: CGFloat) {
rightConstraint.constant = width
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded()
}
}
func setUpView() {
label.text = "Label"
label.textAlignment = .right
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
rightConstraint = view.trailingAnchor.constraint(equalTo: label.trailingAnchor)
rightConstraint.isActive = true
label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
}
}
子类并覆盖了UILabel
。这是每个action(for: CALayer, forKey: String)
决定响应属性更改而应用哪个动画(ref)的地方。当标签位于表格视图中时,我一直在寻找一些奇怪的动画行为。
如果打印UIView
,则会看到key
即将提交与{{1 }}。
实际上,UIKit
的每次更改都会调用UIView.animate(withDuration:)
(这很有意义)。因此,我想标签的内容重绘与其框架更改之间存在冲突。
我认为您应该在不使用setNeedsDisplay
的情况下重新创建标签的正确文本对齐方式。
水平将标签仅固定在右侧。调用UILabel
时,只会更改标签的位置,而不会更改其内容。
答案 1 :(得分:1)
如@ {Gaétanz答案中所述。异常行为归因于单元内部的标签。
您可以通过将“标签”前导约束关系更改为> =来消除故障,并将优先级从1000更改为999。
请参考所附的屏幕截图,以供参考。
当添加优先级小于1000的约束时,它将是可选约束。优先级1000是约束所需的优先级。在这里,如果您添加了优先级999,所有其他优先级为1000的约束将首先布局,而优先级较低的约束将最后布局。
答案 2 :(得分:0)
您正在更改动画块外部的侧视图宽度。将widthConstaint.constant = width
放到动画块中。
func change(width: CGFloat) {
UIView.animate(withDuration: 1.0) {
self.widthConstaint.constant = width
self.view.layoutIfNeeded()
}
}
答案 3 :(得分:0)
根据您的代码,将对View进行动画处理,但不会将约束放置在UIView动画块中。因此,它看起来像是小故障,导致直接更改了帧。请尝试如下更改代码,然后尝试。
func change(width: CGFloat) {
UIView.animate(withDuration: 1.0) {
widthConstaint.constant = width
self.tableView.layoutIfNeeded()
self.view.layoutIfNeeded()
}
}