正在跳过 UIView 动画
UIView animation is being skipped
好的快速背景:我在两个控制器之间进行切换:我的家庭控制器和一个以地图作为视图的控制器。当用户点击搜索栏的 textField 时触发 segue
我已经包含了动画前后的图像
过程如下:
我将搜索栏添加到 let keyWindow = UIApplication.shared.keyWindow
中与 table 视图中相同的位置
let preLeadingConstraint = searchView.leadingAnchor.constraint(equalTo: keyWindow.leadingAnchor, constant: 8)
let preTrailingConstraint = searchView.trailingAnchor.constraint(equalTo: keyWindow.trailingAnchor, constant: -8)
let preTopConstraint = searchView.topAnchor.constraint(equalTo: keyWindow.topAnchor, constant: originY)
NSLayoutConstraint.activate([preLeadingConstraint, preTrailingConstraint, preTopConstraint])
keyWindow.layoutIfNeeded()
这里没问题。另外:搜索栏在此之前激活了高度限制:heightAnchor.constraint(equalToConstant: PlacesSearchView.height).isActive = true
下一步是这个动画(自定义转场):
UIView.animate(withDuration: self.duration, animations: {
homeController.view.frame.origin.x = -Global.width
self.destination.view.frame.origin.x = 0
}) { _ in
homeController.navigationController?.viewControllers.append(self.destination)
self.destination.navigationController?.setNavigationBarHidden(false, animated: true)
}
非常简单,也没有问题
这部分是问题:
我停用了旧的搜索栏限制:
NSLayoutConstraint.deactivate(preConstraints)
我创建了关闭按钮并将其锚定到 keyWindow:
let side: CGFloat = 25
let margin: CGFloat = 8
closeButton?.topAnchor.constraint(equalTo: keyWindow.layoutMarginsGuide.topAnchor, constant: margin).isActive = true
closeButton?.centerXAnchor.constraint(equalTo: keyWindow.centerXAnchor).isActive = true
closeButton?.heightAnchor.constraint(equalToConstant: side).isActive = true
closeButton?.widthAnchor.constraint(equalTo: closeButton!.heightAnchor).isActive = true
然后我将新的约束应用到搜索栏。
topAnchor.constraint(equalTo: closeButton!.bottomAnchor, constant: yAxisMargin).isActive = true
leadingAnchor.constraint(equalTo: keyWindow.leadingAnchor, constant: 0).isActive = true
trailingAnchor.constraint(equalTo: keyWindow.trailingAnchor, constant: 0).isActive = true
并锚定到键盘:
bottomKeyboardConstraint = bottomAnchor.constraint(equalTo: keyWindow.bottomAnchor, constant: -keyboardHeight)
heightConstraint.isActive = false
bottomKeyboardConstraint?.isActive = true
instantiateTableView()
subviewTableView()
那我当然会应用神奇的公式:
UIView.animate(withDuration: 0.5, animations: {
keyWindow.layoutIfNeeded()
// (I also animate background color)
}
但是! 令我惊讶的是...它跳过了动画。直接进入结束状态。就像直接看图 2。我试图做(愚蠢的)事情来让某种动画开始(例如,我测试了这个的简化版本:没有添加也没有停用任何约束,只是尝试改变 topConstraint.constant 到 0 和...同样的事情:搜索栏直接向上,没有任何动画)
我没有得到什么?感谢您的耐心回答,期待您的指点!
更新: 由于某种原因,我忘记将最后一个 UIView.animate
块放在 DispatchQueue.main.async
块中。这样做会导致......有时有动画,大多数时候没有动画。这变得越来越奇怪了。此外,在此之前,我从未将我的任何动画放在 DispatchQueue.main.async
块中,即使是在其他自定义 segue 中,这也很奇怪。
好的,我明白了,事情是这样的:
基本上... DispatchQueue.main.async
是问题的根源。让我解释一下。
首先,让我们明确一点,我在 DispatchQueue.main.async
块内执行 segue:
DispatchQueue.main.async {
self.performSegue(withIdentifier: HomeViewController.storyboardData.segueIdentifiers.places, sender: self)
}
但显然...这还不够。
然后我有了将我的 override func perform()
代码放在 DispatchQueue.main.async
中的想法(是的……我知道!)。所以它看起来像这样:
override func perform() {
DispatchQueue.main.async {
...
}
}
而且...每次都是动画!
动画很奇怪,所以我基本上决定尝试将代码的不同部分放在块中,直到它可以工作并且......它最终可以工作。 (我承认做这种事情有点遗憾)。有兴趣者详情如下:
- 有一部分代码负责在用户单击搜索按钮时设置动画。这在将整个 perform() 代码放入
DispatchQueue.main.async
块之前起作用,所以......我回滚到工作版本
现在负责动画部分,以防用户单击文本字段:现在基本上看起来像这样(segueToEditing 是我创建关闭按钮、删除旧约束、添加新约束和动画的地方):
DispatchQueue.main.async { self.segueToEditing() }
我仍然对我的解决方案的工作原理感到困惑,但我现在知道我不会弄乱 DispatchQueue.main.async
个块。
好的快速背景:我在两个控制器之间进行切换:我的家庭控制器和一个以地图作为视图的控制器。当用户点击搜索栏的 textField 时触发 segue
我已经包含了动画前后的图像
过程如下:
我将搜索栏添加到 let keyWindow = UIApplication.shared.keyWindow
中与 table 视图中相同的位置
let preLeadingConstraint = searchView.leadingAnchor.constraint(equalTo: keyWindow.leadingAnchor, constant: 8)
let preTrailingConstraint = searchView.trailingAnchor.constraint(equalTo: keyWindow.trailingAnchor, constant: -8)
let preTopConstraint = searchView.topAnchor.constraint(equalTo: keyWindow.topAnchor, constant: originY)
NSLayoutConstraint.activate([preLeadingConstraint, preTrailingConstraint, preTopConstraint])
keyWindow.layoutIfNeeded()
这里没问题。另外:搜索栏在此之前激活了高度限制:heightAnchor.constraint(equalToConstant: PlacesSearchView.height).isActive = true
下一步是这个动画(自定义转场):
UIView.animate(withDuration: self.duration, animations: {
homeController.view.frame.origin.x = -Global.width
self.destination.view.frame.origin.x = 0
}) { _ in
homeController.navigationController?.viewControllers.append(self.destination)
self.destination.navigationController?.setNavigationBarHidden(false, animated: true)
}
非常简单,也没有问题
这部分是问题:
我停用了旧的搜索栏限制:
NSLayoutConstraint.deactivate(preConstraints)
我创建了关闭按钮并将其锚定到 keyWindow:
let side: CGFloat = 25
let margin: CGFloat = 8
closeButton?.topAnchor.constraint(equalTo: keyWindow.layoutMarginsGuide.topAnchor, constant: margin).isActive = true
closeButton?.centerXAnchor.constraint(equalTo: keyWindow.centerXAnchor).isActive = true
closeButton?.heightAnchor.constraint(equalToConstant: side).isActive = true
closeButton?.widthAnchor.constraint(equalTo: closeButton!.heightAnchor).isActive = true
然后我将新的约束应用到搜索栏。
topAnchor.constraint(equalTo: closeButton!.bottomAnchor, constant: yAxisMargin).isActive = true
leadingAnchor.constraint(equalTo: keyWindow.leadingAnchor, constant: 0).isActive = true
trailingAnchor.constraint(equalTo: keyWindow.trailingAnchor, constant: 0).isActive = true
并锚定到键盘:
bottomKeyboardConstraint = bottomAnchor.constraint(equalTo: keyWindow.bottomAnchor, constant: -keyboardHeight)
heightConstraint.isActive = false
bottomKeyboardConstraint?.isActive = true
instantiateTableView()
subviewTableView()
那我当然会应用神奇的公式:
UIView.animate(withDuration: 0.5, animations: {
keyWindow.layoutIfNeeded()
// (I also animate background color)
}
但是! 令我惊讶的是...它跳过了动画。直接进入结束状态。就像直接看图 2。我试图做(愚蠢的)事情来让某种动画开始(例如,我测试了这个的简化版本:没有添加也没有停用任何约束,只是尝试改变 topConstraint.constant 到 0 和...同样的事情:搜索栏直接向上,没有任何动画)
我没有得到什么?感谢您的耐心回答,期待您的指点!
更新: 由于某种原因,我忘记将最后一个 UIView.animate
块放在 DispatchQueue.main.async
块中。这样做会导致......有时有动画,大多数时候没有动画。这变得越来越奇怪了。此外,在此之前,我从未将我的任何动画放在 DispatchQueue.main.async
块中,即使是在其他自定义 segue 中,这也很奇怪。
好的,我明白了,事情是这样的:
基本上... DispatchQueue.main.async
是问题的根源。让我解释一下。
首先,让我们明确一点,我在 DispatchQueue.main.async
块内执行 segue:
DispatchQueue.main.async {
self.performSegue(withIdentifier: HomeViewController.storyboardData.segueIdentifiers.places, sender: self)
}
但显然...这还不够。
然后我有了将我的 override func perform()
代码放在 DispatchQueue.main.async
中的想法(是的……我知道!)。所以它看起来像这样:
override func perform() {
DispatchQueue.main.async {
...
}
}
而且...每次都是动画!
动画很奇怪,所以我基本上决定尝试将代码的不同部分放在块中,直到它可以工作并且......它最终可以工作。 (我承认做这种事情有点遗憾)。有兴趣者详情如下:
- 有一部分代码负责在用户单击搜索按钮时设置动画。这在将整个 perform() 代码放入
DispatchQueue.main.async
块之前起作用,所以......我回滚到工作版本 现在负责动画部分,以防用户单击文本字段:现在基本上看起来像这样(segueToEditing 是我创建关闭按钮、删除旧约束、添加新约束和动画的地方):
DispatchQueue.main.async { self.segueToEditing() }
我仍然对我的解决方案的工作原理感到困惑,但我现在知道我不会弄乱 DispatchQueue.main.async
个块。