изменить высоту программно созданного пользовательского inputAccessoryView? быстрый 4

Итак, я делаю приложение для обмена сообщениями, и у меня есть 4 свойства класса:

  1. typingView: UIView!
  2. messageTextView: UITextView!
  3. sendButton: UIButton!
  4. typingViewHeight: NSLayoutConstraint?

typingView - это inputAccessoryView главного представления, которое работает! Он содержит messageTextView и sendButton. Но моя проблема в том, что ... когда количество строк текста в messageTextView увеличивается, я хочу, чтобы высота увеличивалась с помощью анимации (я пока игнорирую уменьшение). И тем самым я решил изменить высоту typingView.

Обнаружение изменения в contentSize работает отлично, я добавил наблюдателя, добавив эту строку

messageTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)

и слушал это с этим переопределением

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)

Внутри этой функции у меня есть (это чрезмерное упрощение и псевдокод, просто предположим, что он работает)

UIView.animate(withDuration: keyboardAnimationDuration) {
    self.typingViewHeight?.constaint += (messageTextView.font?.lineHeight)!
}

Вот мой код для настройки inputAccessoryView:

lazy var typingViewContainer: UIView = {
    // Set up typing view
    typingView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 55))
    typingView.backgroundColor = UIColor.darkGray
    typingView.translatesAutoresizingMaskIntoConstraints = false

    // Set up animated constraints
    typingViewHeight = typingView.heightAnchor.constraint(equalToConstant: typingView.frame.height)
    typingViewHeight?.isActive = true

    // Set up text view
    messageTextView = UITextView()
    messageTextView.translatesAutoresizingMaskIntoConstraints = false
    messageTextView.font = fakeMessageTextView.font
    messageTextView.keyboardType = fakeMessageTextView.keyboardType
    messageTextView.isScrollEnabled = fakeMessageTextView.isScrollEnabled
    messageTextView.alwaysBounceVertical = fakeMessageTextView.alwaysBounceVertical
    messageTextView.text = fakeMessageTextView.text
    messageTextView.textColor = fakeMessageTextView.textColor
    messageTextView.delegate = self
    typingView.addSubview(messageTextView)

    // Constraints
    messageTextView.bottomAnchor.constraint(equalTo: typingView.bottomAnchor, constant: -fakeMessageTextViewBottom.constant).isActive = true
    messageTextView.topAnchor.constraint(equalTo: typingView.topAnchor, constant: fakeMessageTextViewTop.constant).isActive = true
    messageTextView.leftAnchor.constraint(equalTo: typingView.leftAnchor, constant: fakeMessageTextViewBottom.constant).isActive = true
    messageTextView.widthAnchor.constraint(equalToConstant: fakeMessageTextViewWidth.constant).isActive = true

    // Observers
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)  
    messageTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)

    // Set up send button
    sendButton = UIButton(type: fakeSendButton.buttonType)
    sendButton.translatesAutoresizingMaskIntoConstraints = false
    sendButton.setTitle(fakeSendButton.titleLabel?.text!, for: .normal)
    sendButton.titleLabel?.font = fakeSendButton.titleLabel?.font
    sendButton.titleLabel?.shadowColor = fakeSendButton.titleLabel?.shadowColor
    sendButton.addTarget(self, action: #selector(sendPressed(_:)), for: .touchUpInside)
    typingView.addSubview(sendButton)

    // Constraints
    sendButton.heightAnchor.constraint(equalToConstant: fakeSendButtonHeight.constant).isActive = true
    sendButton.widthAnchor.constraint(equalToConstant: fakeSendButtonWidth.constant).isActive = true
    sendButton.bottomAnchor.constraint(equalTo: typingView.bottomAnchor, constant: -fakeSendButtonBottom.constant).isActive = true
    sendButton.rightAnchor.constraint(equalTo: typingView.rightAnchor, constant: -fakeSendButtonRight.constant).isActive = true

    return typingView
}()

override var inputAccessoryView: UIView? {
    get {
        return typingViewContainer
    }
}

override var canBecomeFirstResponder: Bool {
    get {
        return true
    }
}

Но когда я тестирую это и набираю несколько строк, он выводит это в консоли:

2018-04-25 08:52:57.614383-0500 ProxiChat[3351:168967] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(
"<NSLayoutConstraint:0x608000280a50 UIView:0x7f8528a2cda0.height == 73   (active)>",
"<NSLayoutConstraint:0x6040000993c0 UIView:0x7f8528a2cda0.height == 55   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x608000280a50 UIView:0x7f8528a2cda0.height == 73   
(active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Почему есть два ограничения? Я добавил только один. Пожалуйста, помогите, спасибо!

ИЗМЕНИТЬ

Предположим, что мой код для изменения высоты typingView работает, поскольку он работал до того, как я изменил свое представление на настраиваемый inputAccessoryView. Я просто хочу знать, почему он распечатывает эту ошибку, и как я могу исправить ее, установив два ограничения, даже если я добавил только одно?


person Michael Hsu    schedule 25.04.2018    source источник
comment
Вы нашли решение этой проблемы? Я в точной ситуации и не нашел ответа.   -  person Pravalika    schedule 29.05.2020


Ответы (2)


Когда вы создаете вид, вы устанавливаете высоту 55:

typingView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 55))

И затем вы устанавливаете привязку высоты:

typingViewHeight = typingView.heightAnchor.constraint(equalToConstant: typingView.frame.height)
typingViewHeight?.isActive = true

Вот почему вы видите конфликт. Еще одно наблюдение: при установке привязки высоты вы можете активировать ее в той же строке, в которой она создается:

typingViewHeight = typingView.heightAnchor.constraint(equalToConstant: typingView.frame.height).isActive = true

Это не дает вам каждый раз писать лишнюю строку кода.

person Zachary Bell    schedule 25.04.2018
comment
Вы не можете сделать это, чтобы получить ограничение typingViewHeight = typingView.heightAnchor.constraint(equalToConstant: typingView.frame.height).isActive = true - person Aleksandr Honcharov; 25.04.2018
comment
У меня это не работает. Также, если я попробую typingView = UIView(), вместо "<NSLayoutConstraint:0x6040000993c0 UIView:0x7f8528a2cda0.height == 55 (active)>" будет написано "<NSLayoutConstraint:0x6040000993c0 UIView:0x7f8528a2cda0.height == 0 (active)>". Даже когда я создал UIView () без инициализации, он устанавливает высоту по умолчанию равной нулю? - person Michael Hsu; 25.04.2018

В первую очередь о главном

Вместо наблюдения я рекомендую вам использовать метод делегата UITextView для настройки высоты контейнера и вашего текстового представления. Этот код делает тот же трюк, но я думаю, что он более лаконичен и понятен.

func textViewDidChange(_ textView: UITextView) {
        let sizeToFitIn = CGSize(width: textView.bounds.size.width, height: .greatestFiniteMagnitude)
        let newSize = textView.sizeThatFits(sizeToFitIn)
        var newHeight = newSize.height

        ....

        // That part depends on your approach to placing constraints, it's just my example
        textInputHeightConstraint?.constant = newHeight
        inputContainerHeightConstraint?.constant = newHeight + (interfaceFactory.inputContainerHeight - interfaceFactory.textInputMinimumHeight)
    }

Попробуйте обновить свой код следующим образом:

typingViewHeight = typingView.heightAnchor.constraint(equalToConstant: typingView.frame.height)
typingViewHeight?.priority = UILayoutPriority(rawValue: 999)
typingViewHeight?.isActive = true

Если это не помогает, взгляните на этот ответ: https://stackoverflow.com/a/27522511/5147552

person Aleksandr Honcharov    schedule 25.04.2018
comment
Код для обработки изменения contentSize UITextView основан на большом количестве другого кода, который я написал, так что опубликовать его там будет довольно сложно. Я знаю, что это работает, потому что он работал с UITextView до, когда я добавил пользовательский inputAccessoryView. У меня вопрос, если предположить, что я правильно регулирую высоту typingView (не messageTextView), почему это дает мне эту ошибку и не позволяет мне изменить ограничение высоты? - person Michael Hsu; 25.04.2018