【问题标题】:AutoLayout Storyboard constraints - how to modify in code to use this modification across Orientation changesAutoLayout Storyboard 约束 - 如何在代码中修改以跨方向更改使用此修改
【发布时间】:2018-10-13 06:09:42
【问题描述】:

我考虑修改 Storyboard NSLayoutConstraint IBOutlets 值的最佳方法是什么,以使这种修改保持方向/大小类更改。

我已经在情节提要约束中定义了某些尺寸类的已安装属性打开。常规/紧凑,关闭其他尺寸类别,如紧凑/常规。

我可以通过 viewDidAppear() 中的 IBOutlet 从代码中修改此约束的值,但它仅在我旋转设备之前有效。 卸载设备旋转约束后,再次使用旧的故事板值重新安装(或者如果在代码中停用,则再次重新激活)。

所以我尝试在 traitColactionDidChange() 方法中添加额外的修改。但它不起作用,在设置 Stroyboard 约束值之前调用它!所以我的修改被故事板中定义的值覆盖。

然后我尝试了 viewDidLayoutSubviews() (UIViewController) 或 layoutSubviews() (UIView)。在简单视图的情况下,它似乎可以工作,但是如果我添加更多视图修改然后计算会挂起我的旋转应用程序,则它是不可靠的。

因此,作为最后的手段,我在 traitCollectionDidChange() 中添加了 Timer.scheduledTimer() 延迟 1 秒,它似乎可以工作,但它似乎也很奇怪。如果故事板在一秒钟之后设置约束值怎么办,也许苹果会在下一版本的 Swift/iOS 中改变一些东西。我可以转发这样的黑客攻击吗?

我的代码:

 override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        if UIDevice.current.userInterfaceIdiom == .pad  {
            bottomConstraint.isActive = false
        } else if traitCollection.sizeClasses == (.regular, .compact) {
            iphoneLeadingSpacerProportionalWidth = leadingSpacerProportionalWidth.setMultiplier(multiplier: 0.1)
            iphoneTrailingSpacerProportionaWidth = trailingSpacerProportionalWidth.setMultiplier(multiplier: 0.1)
        }
    }

    private var iphoneLeadingSpacerProportionalWidth : NSLayoutConstraint? = nil
    private var iphoneTrailingSpacerProportionaWidth : NSLayoutConstraint? = nil

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if let leadingConstraint = iphoneLeadingSpacerProportionalWidth,
            let trailingConstraint = iphoneTrailingSpacerProportionaWidth {
            NSLayoutConstraint.deactivate([leadingConstraint, trailingConstraint])
        }

        Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (timer) in
            if UIDevice.current.userInterfaceIdiom == .pad  {
                self.bottomConstraint.isActive = false
            } else if self.traitCollection.sizeClasses == (.regular, .compact) {
                self.iphoneLeadingSpacerProportionalWidth = self.leadingSpacerProportionalWidth.setMultiplier(multiplier: 0.1)
                self.iphoneTrailingSpacerProportionaWidth = self.trailingSpacerProportionalWidth.setMultiplier(multiplier: 0.1)
            }
        }
    }

重要!这个 setMultiplier() 使用了我发现的一些扩展,所以不要注意它,如果我设置 constraint.constant = toSomeValue

,它的工作方式相同

【问题讨论】:

    标签: ios swift autolayout nslayoutconstraint


    【解决方案1】:

    您可以在情节提要本身中为不同尺寸类别设置不同的值。见附件。

    如果您仍想通过代码进行更新。您应该使用它来检测方向。

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if UIDevice.current.orientation.isLandscape {
            print("Landscape")
        } else {
            print("Portrait")
        }
    }
    

    【讨论】:

    • 是的,我知道我有这个尺寸的课程。但是我已经为 iPad Landscape 覆盖了 w: R, h: C。这个尺寸等级现在用于 iPad Landscape 和 iPhone Plus、XS Max、XR 的 Landscape。布局非常适合这两种情况,但例如在 iPad 上,我希望有更大的边距 20% 左右,而不是 iPhone 10%。在另一个视图中,我有带有菜单图标的 StackView,并且容器的大小在纵向和布局中发生变化,并且我正在根据此容器视图的大小计算宽度/高度常量。
    • 你认为 viewWillTransition(to size: CGSzie, with coordinator ..) 方法会在约束设置后被调用吗?当屏幕旋转和大小类更改时,也会调用 traitColactionDidChange(),但情节提要的约束是在生命周期的后期设置的。我需要一个可以安全地修改约束而不会延迟此约束修改代码的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多