【问题标题】:Why showing and hiding view from viewWillAppear or viewDidAppear doesn't work为什么从 viewWillAppear 或 viewDidAppear 显示和隐藏视图不起作用
【发布时间】:2017-06-22 13:01:10
【问题描述】:

我最近将一个应用程序从模态 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
}

谢谢

【问题讨论】:

  • 总是viewWillAppear 和其他人中调用super。否则你会破坏一切。
  • view1, button1, ... 来自哪里?
  • 好的。仅供参考,任何以 viewWill/viewDid 开头的东西,都必须调用 super。
  • 作为一般规则,当覆盖 UIKit 类时,调用 super 除非文档明确说明不这样做。
  • 正如@deadbeef 指出的,您应该添加:super.viewWillAppear(animated)super.viewDidAppear(animated)

标签: ios swift uitabbarcontroller viewwillappear


【解决方案1】:

请注意,“它不起作用”确实没有帮助。如果您需要帮助,您需要详细描述您的代码做什么或不做什么。

您的代码有几处问题。

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

在下次更新视图布局之前,更新约束上的常量不会做任何事情。

当您在 viewDidLoad() 中更改布局约束时,它会在布局完成之前发生,因此更改会在下一个布局传递中应用。

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

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

【讨论】:

  • 好的,原来我的问题是我正在重新定位我的视图,但我没有将它们重新定位回原来的位置。我知道这听起来很傻,但是当我从ViewDidLoad 调用customizeApp() 时,完全相同的代码工作正常,但由于您的解释,我能够找到问题所在。仅供参考 - 我不需要打电话给self.view.layoutIfNeeded() 我只是从viewDidAppear 打电话给customizeApp() 并通过调整它们的约束将我的视图重新定位到它们的原始位置。非常感谢您的帮助!
【解决方案2】:

来自Apple Documentation

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

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

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

  1. 使用情节提要文件中的信息实例化视图。

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

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

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

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

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

使用 viewDidLoad 方法添加或删除视图,修改布局约束, 并为您的视图加载数据。通常重写此方法以对从 nib 文件加载的视图执行额外的初始化。

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

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

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

【讨论】:

    猜你喜欢
    • 2014-04-12
    • 1970-01-01
    • 2018-04-19
    • 2011-08-03
    • 2023-02-15
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多