如何在不制作 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 高度约束设置动画?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不“连接”它们的情况下以编程方式访问 NIB 中的 UI 元素?
如何在不使用命令的情况下以编程方式关闭/重启 linux 机器(运行时)
如何在不使用外部主机的情况下以编程方式查找设备的外部 IP 地址?