如何用动画更改UITableView的宽度?

季霍诺夫·亚历山大

UITableView的尺寸在左边UIView,右边在平原UIViewController

  • UITableView连接.top.leading.bottomsuperview
  • UIView连接.top.trailing.bottomsuperview,也有.width
  • UITableView .leading==.trailingUIView

您可以在屏幕截图上看到所有这些约束:

在此处输入图片说明

这是在控制器我的动画的代码,你可以看到我更新.widthUIView,也是我来循环播放动画。

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章