我在主要故事板中进行了相当简单的设置:
我的代码将处理更改的视图活动视图,如下所示:
import Foundation
import UIKit
class ViewController : UIViewController {
@IBOutlet weak var stackView: UIStackView!
@IBOutlet weak var segmentController: UISegmentedControl!
@IBAction func SegmentClicked(_ sender: AnyObject) {
updateView(segment: sender.titleForSegment(at: sender.selectedSegmentIndex)!)
}
override func viewDidLoad() {
updateView(segment: "First")
}
func updateView(segment: String) {
UIView.animate(withDuration: 1) {
if(segment == "First") {
self.stackView.arrangedSubviews[1].isHidden = false
self.stackView.arrangedSubviews[2].isHidden = true
} else {
self.stackView.arrangedSubviews[1].isHidden = true
self.stackView.arrangedSubviews[2].isHidden = false
}
print("Updating views")
print("View 1 is \(self.stackView.arrangedSubviews[1].isHidden ? "hidden" : "visible")")
print("View 2 is \(self.stackView.arrangedSubviews[2].isHidden ? "hidden" : "visible")")
}
}
}
正如您所看到的,当标签名为' First'如果选中,则索引1处的子视图应显示,而隐藏2,当选择任何其他内容时,索引2处的子视图应显示,而1则隐藏。
这似乎首先起作用,如果我慢慢改变视图,但如果我更快一点,索引1处的视图似乎在几次单击后保持永久隐藏,导致索引0处的视图覆盖整个屏幕。我已经放置了一个显示问题的动画和下面的故事板截图。输出显示问题发生时,单击第一个段时两个视图都保持隐藏状态。
有人能告诉我为什么会这样吗?这是一个错误,还是我没有做我应该做的事情?
非常感谢提前!
更新:我似乎能够通过转到第一个>来可靠地重现问题。第二个>第三个>第二个>按顺序排列的第一段。
答案 0 :(得分:38)
错误是在堆栈视图中隐藏和显示视图是累积的。奇怪的苹果虫。如果在堆栈视图中隐藏视图两次,则需要显示两次才能将其恢复。如果你显示三次,你需要隐藏它三次以实际隐藏它(假设它被隐藏起来)。
这与使用动画无关。
因此,如果您在代码中执行此类操作,只有在视图可见时隐藏视图,您才能避免此问题:
if myView.isHidden == false {
myView.isHidden = true
}
答案 1 :(得分:6)
基于Dave Batton的不错答案,你还可以添加一个UIView扩展来使呼叫站点更清洁,IMO。
extension UIView {
var isHiddenInStackView: Bool {
get {
return isHidden
}
set {
if isHidden != newValue {
isHidden = newValue
}
}
}
}
然后你可以调用stackView.subviews[someIndex].isHiddenInStackView = false
,如果你有多个视图可以在堆栈视图中管理而不是一堆if语句,那么这将是有用的。
答案 2 :(得分:2)
最后,在尝试了所有这些建议之后,我仍然无法解决为什么它的表现如此,所以我与Apple联系,要求我提交错误报告。然而,我确实找到了一个解决方案,首先取消隐藏两个视图,这解决了我的问题:
func updateView(segment: String) {
UIView.animate(withDuration: 1) {
self.stackView.arrangedSubviews[1].isHidden = false
self.stackView.arrangedSubviews[2].isHidden = false
if(segment == "First") {
self.stackView.arrangedSubviews[2].isHidden = true
} else {
self.stackView.arrangedSubviews[1].isHidden = true
}
}
}
答案 3 :(得分:1)
根据我所看到的,这种奇怪的行为是由动画持续时间引起的。正如您所看到的,动画完成需要一秒钟,但如果您开始更快地切换segmentControl,那么我认为这就是导致此行为的原因。
您应该做的是在调用方法时停用用户交互,然后在动画完成后重新启用它。
看起来应该是这样的:
func updateView(segment: String) {
segmentControl.userInteractionEnabled = false
UIView.animateWithDuration(1.0, animations: {
if(segment == "First") {
self.stackView.arrangedSubviews[1].isHidden = false
self.stackView.arrangedSubviews[2].isHidden = true
} else {
self.stackView.arrangedSubviews[1].isHidden = true
self.stackView.arrangedSubviews[2].isHidden = false
}
print("Updating views")
print("View 1 is \(self.stackView.arrangedSubviews[1].isHidden ? "hidden" : "visible")")
print("View 2 is \(self.stackView.arrangedSubviews[2].isHidden ? "hidden" : "visible")")
}, completion: {(finished: Bool) in
segmentControl.userInteractionEnabled = true
}
}
虽然这会阻止快速切换(你可能会认为这是一个缺点),但我所知道的另一种解决方法是完全删除动画。
答案 4 :(得分:0)
检查堆栈视图和子视图的配置和自动布局约束,尤其是分段控件。
分段控件使堆栈视图的设置变得复杂,因此我将分段控件从堆栈视图中取出并相对于主视图设置其约束。
通过分段控件退出堆栈视图,设置堆栈视图相对简单,以便您的代码能够正常工作。
重置堆栈视图上的约束,使其位于分段控件下方,并覆盖超级视图的其余部分。在“属性”检查器中,将“对齐”设置为“填充”,将“分布”设置为“均匀填充”,将“内容模式”设置为“缩放为填充”。
删除子视图上的约束,并将其内容模式设置为“缩放至填充”。
调整代码中arrangeSubviews的索引,它应该自动运行。