Подтвердить что ты не робот

Изменение размера входа в AccessViewView динамически в iOS 8

В основном я пытаюсь создать изменение размера UITextView в свойстве inputAccessoryView.

У меня есть viewController с методом canBecomeFirstResponder, возвращающим true, и представление, которое я создаю через пользовательский класс (который получает его из XIB). В этом представлении находится UITextView.

Я пытаюсь изменить размер inputAccessoryView изнутри этого класса. Я попробовал несколько способов: установив рамку directy, попробуйте использовать ограничение по высоте. Кажется, он изменяется только наполовину:

Это в основном то, что я хочу (с автозапуском или без него, но работающий в iOS 7/8 +):

class MessageInputAccessory: UIView, UITextViewDelegate
{
    @IBOutlet weak var textView: UITextView!

    func textViewDidChange(textView: UITextView)
    {
        var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))

        self.frame.size.height = contentSize.height + 20

        self.textView.reloadInputViews()
    }
}

Я нашел этот пост: Изменение фрейма inputAccessoryView в iOS 8. Заявляя, что создается автоматически созданное ограничение. Дело в том, что это не создает ограничения для меня. Ни в коем случае, если автозапуск отключен или включен (также через setTranslatesAutoresizingMaskIntoConstraints()).

4b9b3361

Ответ 1

Он работает для меня в iOS7/iOS8:

class MessageInputAccessory: UIView, UITextViewDelegate {
    private var textView: UITextView!
    private var heightConstraint: NSLayoutConstraint?

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

        commonInit()
    }

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

        commonInit()
    }

    func commonInit() {
        self.userInteractionEnabled = true

        textView = UITextView()
        textView.delegate = self
        textView.bounces = false
        textView.scrollEnabled = false
        textView.layer.cornerRadius = 5
        textView.layer.borderWidth = 1
        textView.layer.borderColor = UIColor.blueColor().CGColor

        self.addSubview(textView)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        textView.frame = self.bounds
    }

    override func addConstraint(constraint: NSLayoutConstraint) {
        self.heightConstraint = constraint

        super.addConstraint(constraint)
    }

    func textViewDidChange(textView: UITextView) {
        var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
        self.frame.size.height = contentSize.height

        if let heightConstraint = self.heightConstraint {
            heightConstraint.constant = self.frame.size.height
        }

        self.textView.reloadInputViews()
    }
}

EDIT: Это работает с xib тоже (iOS7/iOS8):

class MessageInputAccessory: UIView, UITextViewDelegate {
    @IBOutlet var textView: UITextView!
    @IBOutlet var textViewHeightConstraint: NSLayoutConstraint!
    private var heightConstraint: NSLayoutConstraint?

    override func awakeFromNib() {
        textView.layer.cornerRadius = 5
        textView.layer.borderWidth = 1
        textView.layer.borderColor = UIColor.blueColor().CGColor
    }

    override func layoutSubviews() {
        textViewHeightConstraint.constant = self.bounds.size.height

        super.layoutSubviews()
    }

    override func addConstraint(constraint: NSLayoutConstraint) {
        if constraint.firstItem === self {
            self.heightConstraint = constraint
        }

        super.addConstraint(constraint)
    }

    override func addConstraints(constraints: [AnyObject]) {
        super.addConstraints(constraints)
    }

    func textViewDidChange(textView: UITextView) {
        var contentSize = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max))
        self.frame.size.height = contentSize.height

        if let heightConstraint = self.heightConstraint {
            heightConstraint.constant = self.frame.size.height
        }

        self.textView.reloadInputViews()
    }

    override func intrinsicContentSize() -> CGSize {
        return self.bounds.size;
    }
}

Есть мой xib: enter image description here

Это не очень хорошее решение, но оно работает.. Скажите, пожалуйста, если вы знаете лучший способ.

Ответ 2

SWIFT 5 Решение

Если кто-то пытался найти решение в stackoverflow, как я, для представления входных аксессуаров, я сделал простую демонстрационную версию проекта для динамически изменяемого входного аксессуара с UITextView. Он также поставляется с нажимной кнопкой в верхней части UITextView, чтобы продемонстрировать добавленные виды в верхней части представления аксессуара ввода. Все они загружаются в XIB для легкой настройки. Написано в Swift 5, а также заботится о безопасной зоне для устройств X.

class InputAccessoryView: UIView, UITextViewDelegate {

@IBOutlet weak var textView: UITextView!

@IBOutlet weak var accessoryButtonViewHeightConstraint: NSLayoutConstraint!

@IBOutlet weak var accessoryButtonView: UIView!
// MARK: - Init

required init?(coder aDecoder: NSCoder) {

    super.init(coder: aDecoder)

    self.setup()
}

override init(frame: CGRect) {

    super.init(frame: frame)

    self.setup()
}

private func setup() {

    let view = self.viewFromNibForClass()

    view?.frame = self.bounds

    view?.autoresizingMask = [.flexibleHeight, .flexibleWidth]

    self.accessoryButtonViewHeightConstraint.constant = 0

    if let view = view {

        self.addSubview(view)

        self.textView.translatesAutoresizingMaskIntoConstraints = false
    }
}

override func didMoveToWindow() {

    super.didMoveToWindow()

    if let window = self.window {

        self.bottomAnchor.constraint(lessThanOrEqualTo: window.safeAreaLayoutGuide.bottomAnchor).isActive = true
    }
}

private func viewFromNibForClass() -> UIView? {

    let bundle = Bundle(for: type(of: self))

    let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)

    let view = nib.instantiate(withOwner: self, options: nil).first as? UIView

    return view
}

func textViewDidChange(_ textView: UITextView) {

    self.accessoryButtonViewHeightConstraint.constant = 40

    self.accessoryButtonView.alpha = 1

    self.updateHeight(textView.contentSize.height + 20 + self.accessoryButtonViewHeightConstraint.constant)
}

private func updateHeight(_ height: CGFloat) {

    for constraint in self.constraints where constraint.firstAttribute == .height {

        constraint.constant = height
    }
}

@IBAction func accessoryButtonTouchUpInside(_ sender: Any) {

    let height = self.frame.size.height - 40

    self.updateHeight(height)

    self.accessoryButtonViewHeightConstraint.constant = 0
}
}

Вот пример использования: https://github.com/jaysalvador/InputAccessoryView

Ответ 3

Достаточно простое исправление для этого состоит в том, чтобы не изменять фактическое изменение размера inputAccessoryView - если вы знаете максимальную высоту, которая вам понадобится для этого, вы можете создать его на максимальной высоте, сделать его прозрачным и добавить subview который изменяет размеры, как вам нравится.

Детали, необходимые для его работы, это то, что inputAccessoryView должен быть подклассом UIView, содержащим следующее:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    point = [self.innerView convertPoint:point fromView:self];
    return [self.innerView pointInside:point withEvent:event];
}

(где self.innerView - это ваше динамическое изменение размера).

Это заставляет его требовать отступы внутри подвью, но передавать все, что выходит за его пределы.

Основной недостаток, о котором следует помнить, заключается в том, что уведомления о клавиатуре предоставят вам фреймы, содержащие весь входной файл max-height inputAccessoryView. Поэтому, если вы используете их (например, настраиваете вставки), вам нужно сделать дополнительную математику.