iosobjective-cswiftinputaccessoryview

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 inputAccessoryView 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()).


Solution

  • 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.