为什么从 viewWillAppear 或 viewDidAppear 显示和隐藏视图不起作用

Why showing and hiding view from viewWillAppear or viewDidAppear doesn't work

我最近将一个应用程序从模态 viewControllers 转换为 TabBarController 并且有一些代码在转换之前可以正常工作,但现在我很难让它在TabBar 应用程序。

我想做的是根据 UserDefaults 中存储的用户设置更新选项卡中的 UI,这些设置发生在 Settings 选项卡中(ViewController ) 并且我想根据用户设置的设置在不同的选项卡中更新 UI。在转换之前,代码在 ViewDidLoad 中并且工作正常,但现在 TabBar 没有 ViewDidLoad 我正在使用 viewWillAppear,在选项卡激活后立即更新但是不工作。

这是代码...

class UserInputViewController: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()
        // customizeApp() // everything works if called from here
    }

    override func viewWillAppear(_ animated: Bool) {
        customizeApp() // Doesn't work
    }
    override func viewDidAppear(_ animated: Bool) {
        // customizeApp() // Doesn't work
    }

     func customizeApp(){

        if isView1(){
            view1.isHidden = false
        }else{
            view1.isHidden = true
        }

        if isButton1(){
            button1.isHidden = false
        }else{
            button1.isHidden = true
        }

        if isTextField1(){
            textField1.isHidden = false
        }else{
            textField1.isHidden = true
        }

        if isTextField2(){
            textField2.isHidden = false
        }else{
            textField2.isHidden = true
        }

        /// Adjust Screen based on settings
        if textField1.isHidden && textField2.isHidden{
            constraintMainButton.constant = 7
            return
        }
        if textField1.isHidden {
            constraintMainButton.constant = 45
        }
        if textField2.isHidden {
            constraintMainButton.constant = 45
        }
    }

    func isView1()->Bool{// read UserDefaults}
    func isButton1()->Bool{// read UserDefaults}
    func isTextField1()->Bool{// read UserDefaults}
    func isTextField2()->Bool{// read UserDefaults}
}

我也试过viewDidLayoutSubviews,但也没用。

知道哪里出了问题吗?

仅供参考 - 所有值均来自 UserDefaults 的预期。

编辑:

我的问题是我正在重新定位我的观点,但我没有将它们重新定位回原来的位置。我知道这听起来很傻,但是当我从 ViewDidLoad 调用 customizeApp() 并在更改为 UITabBar 之前,完全相同的代码工作正常时,我被这个事实所欺骗。我最终从 viewDidAppear() 方法调用了 customizeApp()

 class UserInputViewController: UIViewController{

    /// ... Code

    override func viewDidAppear(_ animated: Bool) {
        customizeApp()
    }

     func customizeApp(){

        /// ... Code

        /// Adjust Screen based on settings
        if textField1.isHidden && textField2.isHidden{
            constraintMainButton.constant = 7
            return
        }
        if textField1.isHidden {
            constraintMainButton.constant = 45
            return // added
        }
        if textField2.isHidden {
            constraintMainButton.constant = 45
            return // added
        }

        constraintMainButton.constant = 83 // added: Original Position
    }
    /// .... Code
}

谢谢

来自Apple Documentation

正如@deadbeef 所说,在 viewWillAppear 和其他人中调用 super。

加载和显示视图控制器视图的过程

故事板使加载和显示视图控制器视图的过程变得非常简单。 UIKit 在需要时自动从故事板文件中加载视图。作为加载过程的一部分,UIKit 执行以下任务序列:

  1. 使用故事板文件中的信息实例化视图。

  2. 连接所有出口和行动。

  3. 将根视图分配给视图控制器的视图属性。

  4. 调用视图控制器的 awakeFromNib 方法。

    调用此方法时,视图控制器的特征集合为空,视图可能不在最终位置。

  5. 调用视图控制器的 viewDidLoad 方法。

Use viewDidLoad method to add or remove views, modify layout constraints, and load data for your views. Usually override this method to perform additional initialization on views that were loaded from nib files.

在屏幕上显示视图控制器的视图之前,UIKit 为您提供了一些额外的机会来准备这些视图在屏幕上之前和之后。具体来说,UIKit 执行以下任务序列:

  1. 调用视图控制器的 viewWillAppear: 方法让它知道 它的观点即将出现在屏幕上。
  2. 更新视图的布局。
  3. 在屏幕上显示视图。
  4. 当视图显示在屏幕上时调用 viewDidAppear: 方法。

添加、删除或修改视图的大小或位置时,请记住添加和删除适用于这些视图的任何约束。对视图层次结构进行与布局相关的更改会导致 UIKit 将布局标记为脏。在下一个更新周期中,布局引擎使用当前布局约束计算视图的大小和位置,并将这些更改应用于视图层次结构。

请注意 "it doesn't work" 确实没有帮助。如果您需要帮助,您需要详细描述您的代码做什么或不做什么。

您的代码有几处错误。

viewDidLoad()viewWillAppear(_:)viewWillDisappear(_:) 中,您必须始终调用 super。

在下一次更新视图的布局之前,更新约束上的常量不会执行任何操作。

当您在 viewDidLoad() 中更改布局约束时,它发生在布局最终确定之前,因此更改将应用​​到下一个布局阶段。

如果要更改约束,需要调用layoutIfNeeded()。尝试将此添加到您的 customizeApp() 函数中:

func customizeApp() {
  defer {
     self.view.layoutIfNeeded()
  }
}