Swift:来自stackView

时间:2016-10-12 14:37:05

标签: ios iphone swift uistackview

我在主要故事板中进行了相当简单的设置:

  • 包含三个视图的堆栈视图
  • 第一个视图具有固定高度并包含段控制器
  • 其他两个观点没有任何限制,其理念是一次只能激活一个,从而填补可用空间

我的代码将处理更改的视图活动视图,如下所示:

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处的视图覆盖整个屏幕。我已经放置了一个显示问题的动画和下面的故事板截图。输出显示问题发生时,单击第一个段时两个视图都保持隐藏状态。

有人能告诉我为什么会这样吗?这是一个错误,还是我没有做我应该做的事情?

非常感谢提前!

Animation showing issue

Image of stack view in storyboard

更新:我似乎能够通过转到第一个>来可靠地重现问题。第二个>第三个>第二个>按顺序排列的第一段。

5 个答案:

答案 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的索引,它应该自动运行。