Ios 设置tableview高度约束的动画,但动画正在跳跃

Ios 设置tableview高度约束的动画,但动画正在跳跃,ios,swift,uitableview,Ios,Swift,Uitableview,我想为我拥有的tableview的高度约束设置动画。我已经建立了一个小的测试项目。表视图位于容器视图中 我的代码是这样的: import UIKit class ViewController: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var heightConstraint: NSLayoutConstraint! @IBOutlet weak var

我想为我拥有的tableview的高度约束设置动画。我已经建立了一个小的测试项目。表视图位于容器视图中

我的代码是这样的:

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!
    @IBOutlet weak var contentView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
    }

    @IBAction func didTapAnimate(_ sender: Any) {
        heightConstraint.constant = 400
        UIView.animate(withDuration: 1.0, animations: {() in
            self.contentView.layoutIfNeeded()
        })
    }

}

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

}

extension ViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.backgroundColor = UIColor.red
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }

}
问题是,当我按下“动画”按钮时,动画不会顺利发生。桌子首先向上跳到一定高度,然后为其余部分设置动画。示例如下:


我做错了什么?为什么桌子会跳?我需要动画平滑。任何关于这方面的提示或建议都将不胜感激!谢谢

因为您使用了高度约束。常数=400,高度是为了使更大,所以您需要使用约束位置“Y”并在位置Y中移动

  UIView.animate(withDuration: 1.0, animations: {
        self.yourTable.frame = CGRect(x: self.yourTable.frame.origin.x, y: self.view.frame.height - self.yourTable.frame.height - <Where do you want go>, width: self.yourTable.frame.width, height: self.yourTable.frame.height) 
    })
UIView.animate(持续时间:1.0,动画:{
self.yourTable.frame=CGRect(x:self.yourTable.frame.origin.x,y:self.view.frame.height-self.yourTable.frame.height-,width:self.yourTable.frame.width,height:self.yourTable.frame.height)
})

因为您使用高度约束。常数=400,高度是为了使更大,所以您需要使用约束位置“Y”并在位置Y中移动

  UIView.animate(withDuration: 1.0, animations: {
        self.yourTable.frame = CGRect(x: self.yourTable.frame.origin.x, y: self.view.frame.height - self.yourTable.frame.height - <Where do you want go>, width: self.yourTable.frame.width, height: self.yourTable.frame.height) 
    })
UIView.animate(持续时间:1.0,动画:{
self.yourTable.frame=CGRect(x:self.yourTable.frame.origin.x,y:self.view.frame.height-self.yourTable.frame.height-,width:self.yourTable.frame.width,height:self.yourTable.frame.height)
})

添加到
表视图的约束在您的场景中相互冲突。在
情节提要
中检查

我使用了与您相同的代码:

@IBAction func methodAnimate(_ sender: Any) {
    heightConstraint.constant = 400
    UIView.animate(withDuration: 1.0, animations: {() in
        self.contentView.layoutIfNeeded()
    })
}
在这些限制条件下:


动画工作得非常好。

添加到
表视图的约束在您的场景中是冲突的。在
情节提要
中检查

我使用了与您相同的代码:

@IBAction func methodAnimate(_ sender: Any) {
    heightConstraint.constant = 400
    UIView.animate(withDuration: 1.0, animations: {() in
        self.contentView.layoutIfNeeded()
    })
}
在这些限制条件下:


而且动画工作得非常好。

因此,问题不在于动画,而在于UITableView的重新加载。tableview仅保存可见单元格,并加载一个额外的单元格,该单元格大约等于顶部和底部的单元格高度。但是你的身高增长太快了,以至于必须重新加载才能保持可见的单元格,这使得重新加载和表格看起来很紧张。因此,我将如何处理这个问题,首先从tableview的顶部添加一个额外的约束到底部安全区域插图,该约束与您的高度约束成反比。你马上就会明白为什么这里会是这样。很抱歉,我删除了内容视图,但它的工作原理应该是一样的

这是整个设置的图像。

现在来看看代码和技巧。诀窍是,如果要使tableview变大,首先要做的是不带动画,但不要将其向上移动。然后设置我们刚刚添加的顶部约束的动画,使其等于-高度。这样,用户看不到重新加载,但它看起来像是向上增长的。要使其更小,请将其向下移动,然后更改大小,以便用户永远看不到重新加载。下面是代码,我添加了注释,以帮助您理解我所说的内容

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var topTableConstraint: NSLayoutConstraint!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
    }

    @IBAction func didTapAnimate(_ sender: Any) {

        if heightConstraint.constant != 400{
            //first change the height.  The thing that will happen is allow the tableview to load up all of it's rows and will stop the choppy ness
            heightConstraint.constant = 400
            self.view.layoutIfNeeded()
            //now we can move it up and it will appear to grow.
            //with iphone x i would put a view in inside the safearaa above the table as to now see it slide up or load underneath or you could pin your content view to the safe area and clip to bounds and this would work as well
            topTableConstraint.constant = -heightConstraint.constant
            UIView.animate(withDuration: 1.0) {
                self.view.layoutIfNeeded()
            }
        }else{
           //animating down so let's do the reverse order
            topTableConstraint.constant = -100
            UIView.animate(withDuration: 1.0, animations: {
                self.view.layoutIfNeeded()
            }) { (finished) in
                self.heightConstraint.constant = 100
                self.view.layoutIfNeeded()
            }
        }
    }

}

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

}

extension ViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.backgroundColor = UIColor.red
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }

}
结果会像这样。希望这有助于解释问题,并为您解决问题


此外,如果您希望所有单元格均为红色,则需要注册一个单元格,使用dequeueReusableCell而不是创建新单元格。

因此,您的问题不在于动画,而在于UITableView的重新加载。tableview仅保存可见单元格,并加载一个额外的单元格,该单元格大约等于顶部和底部的单元格高度。但是你的身高增长太快了,以至于必须重新加载才能保持可见的单元格,这使得重新加载和表格看起来很紧张。因此,我将如何处理这个问题,首先从tableview的顶部添加一个额外的约束到底部安全区域插图,该约束与您的高度约束成反比。你马上就会明白为什么这里会是这样。很抱歉,我删除了内容视图,但它的工作原理应该是一样的

这是整个设置的图像。

现在来看看代码和技巧。诀窍是,如果要使tableview变大,首先要做的是不带动画,但不要将其向上移动。然后设置我们刚刚添加的顶部约束的动画,使其等于-高度。这样,用户看不到重新加载,但它看起来像是向上增长的。要使其更小,请将其向下移动,然后更改大小,以便用户永远看不到重新加载。下面是代码,我添加了注释,以帮助您理解我所说的内容

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var topTableConstraint: NSLayoutConstraint!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
    }

    @IBAction func didTapAnimate(_ sender: Any) {

        if heightConstraint.constant != 400{
            //first change the height.  The thing that will happen is allow the tableview to load up all of it's rows and will stop the choppy ness
            heightConstraint.constant = 400
            self.view.layoutIfNeeded()
            //now we can move it up and it will appear to grow.
            //with iphone x i would put a view in inside the safearaa above the table as to now see it slide up or load underneath or you could pin your content view to the safe area and clip to bounds and this would work as well
            topTableConstraint.constant = -heightConstraint.constant
            UIView.animate(withDuration: 1.0) {
                self.view.layoutIfNeeded()
            }
        }else{
           //animating down so let's do the reverse order
            topTableConstraint.constant = -100
            UIView.animate(withDuration: 1.0, animations: {
                self.view.layoutIfNeeded()
            }) { (finished) in
                self.heightConstraint.constant = 100
                self.view.layoutIfNeeded()
            }
        }
    }

}

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

}

extension ViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.backgroundColor = UIColor.red
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }

}
结果会像这样。希望这有助于解释问题,并为您解决问题


此外,如果您希望所有单元格均为红色,则需要注册一个单元格,即使用dequeueReusableCell,而不是创建新单元格。

尝试以下操作:请描述内容视图约束?简而言之,从表视图中删除顶部约束。当您更改高度时,表视图正在识别冲突的约束。@Kex将这一行
self.contentView.layoutifneed()
更改为
self.view.layoutifneed()
,并且您的动画效果很好如果@chiragsha所说的不起作用,请显示约束。@chiragsha我告诉他您的解决方案应该起作用。如果没有,他应该分享他的自动布局代码。试试这个:你能描述一下内容视图约束吗?简而言之,从表视图中删除顶部约束。当您更改高度时,表视图正在识别冲突的约束。@Kex将这一行
self.contentView.layoutifneed()
更改为
self.view.layoutifneed()
,并且您的动画效果很好如果@chiragsha所说的不起作用,请显示约束。@chiragsha我告诉他您的解决方案应该起作用。如果没有,他应该分享他的自动布局代码。谢谢。现在工作!谢谢你。现在工作!