Ios 使用动画自动布局视图

Ios 使用动画自动布局视图,ios,swift,animation,autolayout,Ios,Swift,Animation,Autolayout,我有一个自定义视图、自定义布局蓝色、自定义UIView,该视图包含3个子视图,通过使用约束布局锚垂直对齐,每个视图按照以下顺序对齐: 1视图:幻灯片显示红色,自定义UIView 2视图:UIButton黄色 3视图:UIView干灰色 我想当我点击黄色按钮时,SlideLayout红色的高度大小在打开时会增加,在关闭时会减少,使用动画。其他视图必须在动画期间更改位置,并且如果SlideLayout增加/减少,则父视图CustomLayout必须增加/减少其高度大小动画 使用此方法时调用什么方法:

我有一个自定义视图、自定义布局蓝色、自定义UIView,该视图包含3个子视图,通过使用约束布局锚垂直对齐,每个视图按照以下顺序对齐:

1视图:幻灯片显示红色,自定义UIView 2视图:UIButton黄色 3视图:UIView干灰色 我想当我点击黄色按钮时,SlideLayout红色的高度大小在打开时会增加,在关闭时会减少,使用动画。其他视图必须在动画期间更改位置,并且如果SlideLayout增加/减少,则父视图CustomLayout必须增加/减少其高度大小动画

使用此方法时调用什么方法:

UIView.animatewithDuration、delay、选项、动画、完成

我通过添加一个简单的打印来覆盖layoutIfNeeded方法,但它不会在动画期间每次调用

我试过了,但没有达到预期效果。我怎样才能解决这个问题谢谢你

代码:

class CustomLayout: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private func setup() {
        onLayout()
    }

    public func onLayout() {
        print("\(frame.size.height)")
        let MARGIN: CGFloat = 10
        for i in 0 ..< subviews.count {
            let child = subviews[i]
                if i == 0 { // slide layout
                    child.translatesAutoresizingMaskIntoConstraints = false
                    child.topAnchor.constraint(equalTo: topAnchor, constant: MARGIN).isActive = true
                    child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
                    child.widthAnchor.constraint(equalToConstant: frame.size.width - (MARGIN * 2)).isActive = true
                    let enchorHeight = child.heightAnchor.constraint(equalToConstant: child.frame.size.height);
                    enchorHeight.isActive = true
                    (subviews[0] as! SlideDownLayout).enchorHeight = enchorHeight
                }
                else if i == 1 { // button
                    child.translatesAutoresizingMaskIntoConstraints = false
                    child.topAnchor.constraint(equalTo: subviews[0].bottomAnchor, constant: MARGIN).isActive = true
                    child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
                    child.widthAnchor.constraint(equalToConstant: child.frame.size.width).isActive = true
                    child.heightAnchor.constraint(equalToConstant: child.frame.size.height).isActive = true

                }
                else if i == 2 { // uiview  
                    child.translatesAutoresizingMaskIntoConstraints = false    
                    child.topAnchor.constraint(equalTo: subviews[1].bottomAnchor, constant: MARGIN).isActive = true                
                    child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true                
                    child.widthAnchor.constraint(equalToConstant: frame.size.width - (MARGIN * 4)).isActive = true 
                    child.heightAnchor.constraint(equalToConstant: 300).isActive = true               
                    bottomAnchor.constraint(equalTo: child.bottomAnchor, constant: MARGIN).isActive = true

                }        
        }    
    }
}

class SlideDownLayout: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private var HEIGHT: CGFloat = 0
    private var isClosed: Bool = true

    private func setup() {
        HEIGHT = frame.height
        frame.size.height = 0
    }

    public func slideAnimation(view: UIView) {
        print("\(HEIGHT)")
        isClosed = !isClosed
        self.enchorHeight!.constant = self.isClosed ? 0 : self.HEIGHT
         UIView.animate(withDuration: 1, delay: 0, options: .curveEaseInOut, animations: {
            self.superview?.layoutIfNeeded()
            view.layoutIfNeeded()
         }, completion: nil)
    }

    override func layoutIfNeeded() {
        print("...")
        super.layoutIfNeeded()
    }

    var enchorHeight: NSLayoutConstraint? = nil
}

class ViewController: UIViewController {

    @IBOutlet weak var customLayout: CustomLayout!
    @IBOutlet weak var slideDownLayout: SlideDownLayout!

    override func viewDidLoad() {
        super.viewDidLoad()

        customLayout.translatesAutoresizingMaskIntoConstraints = false
        customLayout.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        customLayout.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
        customLayout.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
        customLayout.topAnchor.constraint(equalTo: view.topAnchor).isActive = true

    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    @IBAction
    func buttonListener(_ sender: Any) {
        slideDownLayout.slideAnimation(view: self.view)
    }
}

当您要创建动态视图时,不要更改帧,而是更改约束的常量,因为帧不会向下推父视图,所以请创建要设置动画的视图的高度约束,并控制其常量值

你可以试试

class CustomLayout: UIView {

   var heightCon:NSLayoutConstraint!

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private func setup() {
        onLayout()
    }

    public func onLayout() {
        print("\(frame.size.height)")
        let MARGIN: CGFloat = 10
        for i in 0 ..< subviews.count {
            let child = subviews[i]
                if i == 0 { // slide layout
                    child.translatesAutoresizingMaskIntoConstraints = false
                    child.topAnchor.constraint(equalTo: topAnchor, constant: MARGIN).isActive = true
                    child.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
                    child.widthAnchor.constraint(equalToConstant: frame.size.width - (MARGIN * 2)).isActive = true
                   heightCon =  child.heightAnchor.constraint(equalToConstant: child.frame.size.height) 
                   heightCon.isActive = true 
                }

尝试使用stackViewthank you,我看不到你的代码更新我按照你说的做了,动画工作,但父级大小没有增加或减少,我更新了我的代码钩住最底部视图的底部约束以更新我的代码,我有底部约束,但打开时视图不从顶部开始,且底部边距超过I=2处视图的父视图集高度谢谢您的帮助我将此行替换为child.bottomAnchor.constraintequalTo:bottomAnchor,constant:margin.isActive=true by bottomAnchor.constraintequalTo:child.bottomAnchor,常量:MARGIN.isActive=true child i=2 CustmLayout,现在工作正常
    public func slideAnimation() {
        print("\(HEIGHT)")

         isClosed = !isClosed

         let ss = self.superview as! CustomLayout

         ss.heightCon.constant = self.isClosed ? 0 : self.HEIGHT

         UIView.animate(withDuration: 1, delay: 0, options: .curveEaseInOut, animations: { 
            ss.layoutIfNeeded()
         }, completion: nil)
    }