应用程序在后台运行时重置约束 - iOS 13

Posted

技术标签:

【中文标题】应用程序在后台运行时重置约束 - iOS 13【英文标题】:Constraints resets when app is going in background - iOS 13 【发布时间】:2020-02-11 01:19:47 【问题描述】:

我已经正常设置了视图的前导、尾随约束。我已将其高度设置为静态 325。对于底部约束,我设置了 2 个约束 1. 主视图的底部约束到视图的底部约束。 2.主视图的底部约束到视图的顶部约束。现在,在用户的操作中,我只显示带有动画的隐藏视图。因此,当视图显示在屏幕上并且应用程序进入后台时,视图的约束会自动更改并且视图会被隐藏。此问题仅在 ios 13 设备中出现。

我尝试更新其对 viewWillAppear() 的约束,但在 iOS 13 中,当应用从后台激活时,也不会调用 ViewControllers 的 viewWillAppear。我也不认为这是更新约束的好主意。

class ViewController: UIViewController 

    @IBOutlet weak var topConstraint: NSLayoutConstraint!
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!

    override func viewDidLoad() 
        super.viewDidLoad()
    

    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(true)
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) 
            self.topConstraint.isActive = false
            self.bottomConstraint.isActive = true
            UIView.animate(withDuration: 0.3) 
                self.view.layoutIfNeeded()
            
        
    

我不希望在应用状态从前台更改为后台时更改或更新我的约束,反之亦然。

请帮帮我。

TIA

【问题讨论】:

您将约束与明确的框架设置混合在一起,这通常会导致问题。不太清楚你想要什么......当你的视图加载时,你想将contentView定位在底部下方(所以它是“屏幕外”),然后你想动画它向上移动到视图中......然后,应用程序转到后台,并且您希望在应用程序返回前台时仍显示视图?没有新动画? 是的。我只想这样。实际上,我在 viewWillAppear() 中编写的代码是在用户操作时执行的。但出于解释的目的,我创建了一个演示。 假设您的动画位置/大小仅在约束条件下正常工作(没有明确的.frame = ... 语句),那么您的代码应该可以正常工作。 ViewDidLoad() 应该在应用程序从后台转换到前台时调用,除非您在该事件上运行了一些其他代码。 【参考方案1】:

也遇到了这个问题。请注意,如果未在 Interface Builder 中检查 Installed,约束会不断重置。因此,作为解决方法,将所有约束 Installed 保留在 IB 中,并仅在代码中更改 isActive 状态。

【讨论】:

这实际上对我不起作用,因为如果我将 isActive 设置为 false,那么当应用程序进入后台并返回时,它会重新激活。 这解决了我的问题,即当用户更改为暗模式时,整个布局会变得疯狂。 这对我也不起作用 - 除了情节提要中的冲突约束之外,后来一些约束为零(我认为是由于冲突)。有效的方法是将它们设置在 viewDidLayoutSubviews 中。【参考方案2】:

对我有用的解决方法是监听 UIApplication.willEnterForegroundNotification,并在此时将 isActive 设置为所有约束。

此通知似乎是在系统(错误地)将所有约束重置为其 IB 状态并且应用再次可见之前发布的。所以现在是修复约束的最佳时机。

一个警告:当您的约束包含在自动调整大小的表格视图单元格中时,此通知似乎在系统计算单元格高度之后触发。因此,您需要在更新约束后触发表格视图以重新计算单元格高度(有关如何执行此操作的信息,请参阅this question)。

【讨论】:

【参考方案3】:

我发现这个问题只发生在 iOS 13.0 及以上版本,请尝试在 ViewDidLayoutSubviews 中进行约束更改

      override func viewDidLayoutSubviews() 
    super.viewDidLayoutSubviews()
            self.bottomConstraint.isActive = false
            self.topConstraint.isActive = true
    self.view.layoutIfNeeded()

【讨论】:

它就像一个魅力。但为什么它只发生在 iOS 13.0 中呢?以及为什么 viewWillAppear 没有被调用?【参考方案4】:

您可以通过设置优先级和翻转值来实现解决方案。

 if !isShowing
       self.bottomConstraint.priority = UILayoutPriority(rawValue: 250)
       self.topConstraint.priority = UILayoutPriority(rawValue: 750)
   else
       self.bottomConstraint.priority = UILayoutPriority(rawValue: 750)
       self.topConstraint.priority = UILayoutPriority(rawValue: 200)
   
   isShowing = !isShowing
   self.subview.layoutIfNeeded()

【讨论】:

【参考方案5】:

如果您需要知道“当应用程序从后台转到前台时我如何通知”。您应该使用 NotificationCenter 向所有人发送信号。但这是一个不好的做法。

也许你可以说出你的目标,我们可以给你不同的方法。

【讨论】:

【参考方案6】:

好吧,我得到了解决方案。实际上,我们不能说它是解决方案。我只是在 iOS 13.1 或更高版本的设备上运行相同的代码,问题就消失了。 所以现在我可以说这个问题只发生在 iOS 13.0 中。

【讨论】:

【参考方案7】:

每当我尝试更新在情节提要上设置了变化的约束的constant 时,我也遇到了类似的问题。要解决这个问题,只需删除所有变体并以编程方式设置它们。

【讨论】:

以上是关于应用程序在后台运行时重置约束 - iOS 13的主要内容,如果未能解决你的问题,请参考以下文章

ios13音频流在后台被切断

求教UNITY在IOS设备上后台运行问题

应用程序进入后台时如何在 iOS 13 上显示自定义启动画面?

为啥我在 iOS 13 中的应用程序在被用户终止时通过静默推送在后台唤醒

ios应用程序在后台使用SwiftUI时如何播放SystemSound

iOS 13 在后台没有收到 VoIP 推送通知