我UITableView
的尺寸在左边UIView
,右边在平原UIViewController
UITableView
连接.top
,.leading
和.bottom
的superview
UIView
连接.top
,.trailing
和.bottom
的superview
,也有.width
UITableView
.leading
==.trailing
的UIView
您可以在屏幕截图上看到所有这些约束:
这是在控制器我的动画的代码,你可以看到我更新.width
的UIView
,也是我来循环播放动画。
class ViewController: UIViewController {
@IBOutlet var widthConstaint: NSLayoutConstraint!
@IBOutlet var tableView: UITableView!
@IBOutlet var watchContainerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
start()
}
func start() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
if self.widthConstaint.constant == 50 {
self.change(width: 100)
} else {
self.change(width: 50)
}
self.start()
}
}
func change(width: CGFloat) {
widthConstaint.constant = width
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded()
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 300
}
}
结果,您可以在.gif上看到这一点,对于没有这种故障的平滑动画我应该怎么做?
更新
I tried to reproduce the UILabel
wrong behavior with my own UIView
subclass:
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()
}
}
The view draws a little blue rectangle at its right, as a text. And… well… the animation is also good!
But if I change the contentMode
to left
(the default value is scaleToFill
):
The blue square jumps from one place to the other.
So, I found out this is not only related to the UILabel
's textAlignment
. It's its combinaison with the default left
content mode of the UILabel
.
contentMode
defines how the content should be adjusted if the content's size and the bounds size are different - this is case during the animation, the view redraws itself with its new size right before being resized.
So
label.contentMode = .left // default
label.textAlignment = .left
will behave as:
label.contentMode = .right
label.textAlignment = .right
PREVIOUS ANSWER
I spent some time on your problem. Guess what?
It's not related to the table view at all. It's because of the .right
text alignment of the label.
You can reproduce the glitch with a simple 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
}
}
Why?
To find out the error, I created a UILabel
subclass and overrode action(for: CALayer, forKey: String)
. It's where each UIView
decides which animation to apply in response to a property change (ref). I was looking for some weird animation behaviors when a label is inside a table view.
If you print key
, you'd see that actions are requested for the position, the bounds and the contents of the label when UIKit
is about to commit the animations related to your UIView.animate(withDuration:)
call.
实际上,setNeedsDisplay
每次UILabel
改变an的大小时都会调用,这称为sens。因此,我想标签的内容重绘与其框架更改之间存在冲突。
我认为您应该在不使用的情况下重新创建标签的正确文本对齐方式textAlignment = .right
。
水平将标签仅固定在右侧。当layoutIfNeeded
将被调用,只有标签的位置会发生变化,而不是它的内容。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句