约束不会在自定义UIView的方法中更新

时间:2016-01-18 02:10:16

标签: ios swift uiview nslayoutconstraint

我试图通过在约束的常量中添加/减去键盘的高度来显示和隐藏键盘时更新按钮的约束。

我之前有过这个工作,但经过一些重新考虑后,它已经停止工作了。以前,keyboardWillShow:keyboardWillHide:的实现完全如下所示。我曾尝试使用setNeedsUpdateConstraintssetNeedsLayout尝试强制刷新,但无济于事。

在进行一些简单的print()调试时,buttonHorizontalConstraint.constant确实会更新,但这些更改并未直观反映。

RegistrationNameView.swift

class RegistrationNameView: UIView {

    let questionLabel: UILabel = {
        let label = UILabel()

        label.font = UIFont.systemFontOfSize(21.0)
        label.text = "Hey, what's your name?"
        label.textAlignment = .Center
        label.textColor = UIColor.lightGrayColor()
        label.translatesAutoresizingMaskIntoConstraints = false

        return label
    }()
    let nameField: UITextField = {
        let field = UITextField()

        field.autocorrectionType = .No
        field.font = UIFont.boldSystemFontOfSize(28.0)
        field.placeholder = "Full name"
        field.returnKeyType = .Next
        field.textAlignment = .Center
        field.translatesAutoresizingMaskIntoConstraints = false

        return field
    }()
    let nextButton: UIButton = {
        let button = UIButton()

        button.setTitle("Continue", forState: .Normal)
        button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        button.titleLabel?.font = UIFont.boldSystemFontOfSize(17.0)
        button.backgroundColor = UIColor(red: 0.263, green: 0.910, blue: 0.847, alpha: 1)
        button.layer.cornerRadius = Global.UISizes.CornerRadius
        button.translatesAutoresizingMaskIntoConstraints = false
        button.contentEdgeInsets = UIEdgeInsetsMake(16.0, 0, 16.0, 0)

        return button
    }()

    var buttonHorizontalConstraint = NSLayoutConstraint()

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.backgroundColor = UIColor.whiteColor()

        // Add subviews
        self.addSubview(questionLabel)
        self.addSubview(nameField)
        self.addSubview(nextButton)

        nameField.becomeFirstResponder()

        // Constraint helpers
        let spacer = Global.UISizes.SpacingUnit
        let margins = self.layoutMarginsGuide

        let layoutConstraints: [NSLayoutConstraint] = {
            var constraints = [NSLayoutConstraint]()

            // Title Label Constraints

            constraints.append(
questionLabel.bottomAnchor.constraintEqualToAnchor(nameField.topAnchor, constant: -(spacer * 2)))
            constraints.append(questionLabel.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor))
            constraints.append(questionLabel.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor))

            // Description Label Constraints
            constraints.append(nameField.topAnchor.constraintEqualToAnchor(margins.centerYAnchor, constant: spacer * -12))
            constraints.append(nameField.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor))
            constraints.append(nameField.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor))

            // Sign Up Button Constraints
            self.buttonHorizontalConstraint = nextButton.bottomAnchor.constraintEqualToAnchor(margins.bottomAnchor, constant: -(spacer * 2))
            constraints.append(self.buttonHorizontalConstraint)
            constraints.append(nextButton.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor))
            constraints.append(nextButton.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor))

            return constraints
        }()
        NSLayoutConstraint.activateConstraints(layoutConstraints)

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func keyboardWillShow(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size {
            self.buttonHorizontalConstraint.constant -= keyboardSize.height
        }
    }

    func keyboardWillHide(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size {
            self.buttonHorizontalConstraint.constant += keyboardSize.height
        }
    }

}

RegistrationNameViewController.swift

class RegistrationNameViewController: UIViewController {

    var nameView: RegistrationNameView! { return self.view as! RegistrationNameView }

    override func viewDidLoad() {
        super.viewDidLoad()

        let nameView = RegistrationNameView(frame: CGRectZero)
        nameView.nextButton.addTarget(self, action: "nextStep:", forControlEvents: .TouchUpInside)
        self.view = nameView
    }

    func nextStep(sender: AnyObject) {
        print("going to the next step \(sender)")

        let credentialsViewController = RegistrationCredentialsViewController()
        self.navigationController?.pushViewController(credentialsViewController, animated: true)
    }

}

RegistrationNavigationController.swift

class RegistrationNavigationController: UINavigationController, UINavigationControllerDelegate {

    var nameViewController: RegistrationNameViewController = RegistrationNameViewController()
    var credViewController: RegistrationCredentialsViewController = RegistrationCredentialsViewController()

    override init(rootViewController: UIViewController) {
        super.init(rootViewController: rootViewController)

        self.delegate = self
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {

        let type = String(viewController.dynamicType)

        switch type {
        case "RegistrationNameViewController":
            // Add keyboard notifications to RegistrationNameViewController
            NSNotificationCenter.defaultCenter().addObserver(nameViewController.view,
                selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
            NSNotificationCenter.defaultCenter().addObserver(nameViewController.view,
                selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

        case "RegistrationCredentialsViewController":
            // Remove keyboard notifications to RegistrationNameViewController before
            // registering for new notifications
            NSNotificationCenter.defaultCenter().removeObserver(nameViewController.view)

            // Add keyboard notifications to RegistrationCredentialsViewController
            NSNotificationCenter.defaultCenter().addObserver(credViewController.view,
                selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
            NSNotificationCenter.defaultCenter().addObserver(credViewController.view,
                selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

        default:
            print("Default")
        }

    }

}

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

经过一番挖掘后,我自己解决了这个问题。

我认为问题在于NSNotificationCenter观察者注册是在后台线程上发生的,这导致实际影响UI的方法实际上没有改变UI。

我没有在navigationController:willShowViewController:animated:中注册观察者,而是在viewWillAppear中注册观察者,并在viewWillDisappear中取消注册。这种情况发生在RegistrationNameViewController而不是RegistrationNavigationController

RegistrationNameViewController.swift

override func viewWillAppear(animated:         
    NSNotificationCenter.defaultCenter().addObserver(self.view,
            selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self.view,
            selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

    (self.view as! RegistrationNameView).nameField.becomeFirstResponder()
}

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self.view)
}

这使得navigationController:willShowViewController:animated:不再需要,可以从RegistrationNavigationController.swift

中删除