当前位置: 首页 > 知识库问答 >
问题:

使用动画自动布局视图

洪知
2023-03-14

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

  • 1视图:幻灯片(红色,自定义UIView)

我想,当我单击按钮(黄色)时,如果使用动画打开,SlideLayout(红色)的高度大小会增加,如果关闭,则会减少。和其他视图必须在动画期间更改位置,如果SlideLayout增加/减少,则父视图(CustomLayout)必须增加/减少其高度大小(动画)。

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

UIView.animate(带持续时间、延迟、选项、动画、完成)

我通过添加一个简单的打印来覆盖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)
    }
}

共有1个答案

尹承业
2023-03-14

当您想要制作动态视图时,不要更改框架,而是更改约束的常量,因为框架不会将父级向下推,因此将要动画的视图的高度约束设置为IBOutlet并控制它的常量值

你可以试试看

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 
                }

//

    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)
    }
 类似资料:
  • 当我打开视图控制器时,我有一个从顶部飞出的视图。我已将UIView的Y约束设置为-200,当视图加载时,将调用以下内容,一切正常: 但是现在我有一个关闭按钮,它应该将动画回到-200位置,然后从屏幕上删除视图控制器。但是这个动画没有发生。视图控制器被直接删除。这是我正在做的: 我提到了这个链接。这似乎对他们有效,但对我无效。请帮忙。

  • 许多有关自动布局约束动画的教程建议更新约束的常量属性,然后在动画块中调用。 我的处境有点棘手。我有一个包含3个子视图的视图。此超级视图的高度不是固定的-它是按其子视图的高度之和计算的。在某些情况下,我要求这3个子视图中的一个子视图切换其高度(它在0和30之间变化,即我希望平滑地隐藏和显示它)。代码类似于此: 不幸的是,这并不像我预期的那样有效。我可以看到子视图高度的平滑变化,但在为子视图高度约束设

  • 我遇到了自动布局的问题,似乎无法找到应该很容易实现的答案。 我有以下视图层次结构: 标签上的前导/尾随限制使它们在更薄的设备上更高(iPhone 4s vs iPhone 6)。 为了让UIScrollview正常工作,我需要在UIScrollView内部设置UIView的高度约束,以避免出现“不明确的高度”警告。 但在iPhone 4s上运行时,UIView不够高,无法容纳它的子视图。 到目前为

  • 我正在努力为新的iPhone5配置我的应用程序。所以我开始研究Cocao touch的自动布局指南([链接][1])和WDC大师班。 但有一件事我还不清楚。如何设置视图的动画。 在我以前的应用程序中,我使用了常规的UIView动画,如: 或CGAffineTransform方法。 有人能告诉我在使用自动布局时最好的解决方法是什么吗,因为我无法引用框架并且不再进行框架声明?设置计时器以及删除和添加约

  • 关于UITableViewCell高度动画,在堆栈溢出方面有很多类似的问题,但对于新的iOS8自动布局驱动的表视图,这些问题都不起作用。我的问题: 自定义单元格: 注意旋转木马高度限制。这是内容视图的子视图(唯一的子视图)的高度约束。 然后,在“查看我要展开的所有操作”单元上,我的代码: 如您所见,我尝试使用这个很好的旧解决方案: 您可以在选中UITableViewCell时设置高度更改的动画吗?

  • 当前为 5.4 版本,稍后将升级到 5.5。在 5.5 中,本节内容被拆分成了多个小节。 使用动画视图 在 Unity 中,动画视图用于预览和编辑游戏对象的动画剪辑。动画视图可以通过菜单 Window -> Animation 打开。 查看游戏对象上的动画 动画视图和层级视图、场景视图以及检视视图紧密耦合。类似于检视视图,动画视图将显示当前选中对象的动画的时间轴和关键帧。你也可以在层级视图或场景视