Wesley Wesley - 7 months ago 17
Swift Question

Resize inputAccessoryView dynamically in iOS 8

Basically I am trying to create a resizing UITextView within a inputAccessoryView property.

I have a viewController with the method canBecomeFirstResponder returning true and a view I instantiate via a custom class (which gets it from a XIB). Within this view is a UITextView located.

I try to resize the complete inputAccessoryView from inside of that class. I tried in in a few ways: setting the frame directy, try to use a height constraint. It appears it resizes only half way:

This is basically what i want (with or without autolayout, but working in 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()
}
}


I have found this post: Changing the frame of an inputAccessoyView in iOS 8. Stating that a automatically created constraint is being created. The thing is, it does not create the constraint for me. In no way, with autolayout disabled or enabled (also via setTranslatesAutoresizingMaskIntoConstraints()).

Answer

It works for me in 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: This works with xib too (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;
    }
}

There is my xib: enter image description here

It is not a very good solution, but it works.. Please tell me if you know a better way.

Comments