如何在不制作 IBOutlet 的情况下以编程方式在 Swift 中为 UIView 高度约束设置动画?

Posted

技术标签:

【中文标题】如何在不制作 IBOutlet 的情况下以编程方式在 Swift 中为 UIView 高度约束设置动画?【英文标题】:How animate UIView height constraint in Swift programmatically without making an IBOutlet? 【发布时间】:2018-06-21 06:36:26 【问题描述】:

我创建了一个按钮,它连接到顶部,前导和尾随,并且具有固定的高度。当我点击按钮时,新的 UIView 实例应该出现动画。

import UIKit

class ViewController: UIViewController 

var topButton = UIButton()
var myView = UIView()

override func viewDidLoad() 
    super.viewDidLoad()

    topButton = UIButton(type: .roundedRect)
    topButton.setTitle("Add Acctivity", for: .normal)
    topButton.backgroundColor = UIColor.purple
    topButton.setTitleColor(UIColor.white, for: .normal)
    topButton.titleLabel?.font = UIFont(name: "System", size: 26)
    topButton.translatesAutoresizingMaskIntoConstraints = false
    topButton.addTarget(self, action: #selector(expandMenu), for: .touchUpInside)
    view.addSubview(topButton)

    topButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
    topButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
    topButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
    topButton.heightAnchor.constraint(equalToConstant: 70).isActive = true

    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)
    myView.topAnchor.constraint(equalTo: view.topAnchor, constant: 70).isActive = true
    myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
    myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
    myView.heightAnchor.constraint(equalToConstant: 100).isActive = true



@objc func expandMenu() 

   myView.heightAnchor.constraint(equalToConstant: 300).isActive = true

    UIView.animate(withDuration: 1) 

        self.view.layoutIfNeeded()
    





有趣的是,当我将高度设置为小于动画的初始值时。

当人们从情节提要创建 IBOutlet 然后更改其常量值时,我看到了许多教程。但我想知道如何以编程方式做到这一点。

【问题讨论】:

在解决您的问题之前,您为什么不想使用 Outlets/IB? 您可以使用 IBOutlet 实现此目的。我想知道你为什么不想那样做! 我不知道如何在代码中做到这一点...我看到了一些示例,当在情节提要中创建按钮然后从按钮高度约束创建 IBOutlet 时。但在我的示例中,一切都在代码中。 所以,为了确保我明白你的意思,myView 默认的高度应该是 100,点击按钮时它的高度应该是 300,对吗? 正确,艾哈迈德。 【参考方案1】:

您的代码中的问题是您正试图重新激活另一个描述myView 高度的约束,方法是(在expandMenu() 中):

myView.heightAnchor.constraint(equalToConstant: 300).isActive = true

我假设您收到类似于以下内容的运行时警告:

[LayoutConstraints] 无法同时满足约束。 以下列表中的至少一个约束可能是一个 你不想要。试试这个:(1)查看每个约束并尝试 找出你没想到的; (2) 找到添加的代码 不需要的约束或约束并修复它。 ( "NSLayoutConstraint:0x60400008e5b0 UIView:0x7fa16a419450.height == 100 (active)>", “NSLayoutConstraint:0x608000097e30 UIView:0x7fa16a419450.height == 300(活动)>” )

将尝试通过打破约束来恢复

在 UIViewAlertForUnsatisfiableConstraints 创建一个符号断点 在调试器中捕获它。中的方法 UIView 上的 UIConstraintBasedLayoutDebugging 类别列于 也可能有帮助。

表示myView已经有了高度的约束,即(在viewDidLoad()中):

myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

您应该改为更改同一约束的 constant 值。你可以这样实现:

NSLayoutConstraint 声明为实例变量:

var myViewHeightConstraint: NSLayoutConstraint!

viewDidLoad():

myViewHeightConstraint = NSLayoutConstraint(item: myView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0.0, constant: 100)
myViewHeightConstraint.isActive = true

代替:

myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

最后,在expandMenu()

myViewHeightConstraint.constant = 300

代替:

myView.heightAnchor.constraint(equalToConstant: 300).isActive = true

输出:


此外:

如果您的目标是让同一个按钮实现展开/折叠行为,您只需将其实现为(在 expandMenu() 中):

myViewHeightConstraint.constant = myViewHeightConstraint.constant == 300 ? 100 : 300

【讨论】:

酷酷,它有效,但为什么我需要参考?有什么方法可以在不创建引用变量的情况下更改常量值? @Tigran 您可以认为使用约束类似于使用任何 IBOutlet,它必须具有参考,因为您不能为同一个锚添加多个约束,您必须编辑存在一个(粗略地说,在某些时候你试图添加多个约束来判断视图的高度是多少,这会产生冲突)。【参考方案2】:

constraint 方法返回一个NSLayoutConstraint。您可以将其分配给类级别变量:

var heightConstraint: NSLayoutConstraint!

override func viewDidLoad() 
    // ...

    heightConstraint = myView.heightAnchor.constraint(equalToConstant: 100)
    heightConstraint.isActive = true

然后您将拥有一个与IBOutlet 非常相似的属性heightConstraint。您可以像为 IBOutlet 约束设置动画一样对其进行动画处理。

【讨论】:

谢谢,它有效,但我为什么在没有引用变量 myView.heightAnchor.constraint(equalToConstant: 100).isActive = true 的情况下更改值时它不起作用 @Tigran 因为您正在更改expandMenu 中的另一个不同约束。使用引用变量,您可以确保修改相同的约束。

以上是关于如何在不制作 IBOutlet 的情况下以编程方式在 Swift 中为 UIView 高度约束设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不编码窗口状态的情况下以编程方式终止 NSApp?

如何在不“连接”它们的情况下以编程方式访问 NIB 中的 UI 元素?

如何在不使用命令的情况下以编程方式关闭/重启 linux 机器(运行时)

如何在不使用外部主机的情况下以编程方式查找设备的外部 IP 地址?

如何在不使用第三方的情况下以编程方式从 Chase 下载我的银行交易?

如何在不使用 HTML 表单的情况下以编程方式将 POST 请求发送到 JSF 页面?