Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Swift - Dynamically increase height of UITextView and parent UIView

I almost have the whole moving a UITextView above the keyboard, increasing/decreasing its height based on the amount of text and then returning it to its original position. However, I'm having trouble getting the parent UIView to grow along with the UITextView.

enter image description hereenter image description hereenter image description here

If I uncomment the last line of the updateParentView() method to update the parent UIView to its updated size, nothing changes size, including the UITextView.

class ViewController: UIViewController, UITextViewDelegate {

    var kPreferredTextViewToKeyboardOffset: CGFloat = 0.0
    var keyboardFrame: CGRect = CGRect.nullRect
    var keyboardIsShowing: Bool = false

    @IBOutlet weak var commentView: UIView!
    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var sendButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

        // Make it look like UITextField
        self.textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
        self.textView.sizeToFit()
        let lightestGrayColor: UIColor = UIColor( red: 224.0/255.0, green: 224.0/255.0, blue:224.0/255.0, alpha: 1.0 )
        self.textView.layer.borderColor = lightestGrayColor.CGColor
        self.textView.layer.borderWidth = 0.6
        self.textView.layer.cornerRadius = 6.0
        self.textView.clipsToBounds = true
        self.textView.layer.masksToBounds = true
    }

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

    func keyboardWillShow(notification: NSNotification)
    {
        self.keyboardIsShowing = true

        if let info = notification.userInfo {
            self.keyboardFrame = (info[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
            self.arrangeViewOffsetFromKeyboard()
        }

    }

    func keyboardWillHide(notification: NSNotification)
    {
        self.keyboardIsShowing = false

        self.returnViewToInitialFrame()
    }

    func arrangeViewOffsetFromKeyboard()
    {
        var theApp: UIApplication = UIApplication.sharedApplication()
        var windowView: UIView? = theApp.delegate!.window!

        var textFieldLowerPoint: CGPoint = CGPointMake(self.commentView!.frame.origin.x, self.commentView!.frame.origin.y + self.commentView!.frame.size.height)

        var convertedTextViewLowerPoint: CGPoint = self.view.convertPoint(textFieldLowerPoint, toView: windowView)

        var targetTextViewLowerPoint: CGPoint = CGPointMake(self.commentView!.frame.origin.x, self.keyboardFrame.origin.y - kPreferredTextViewToKeyboardOffset)

        var targetPointOffset: CGFloat = targetTextViewLowerPoint.y - convertedTextViewLowerPoint.y
        var adjustedViewFrameCenter: CGPoint = CGPointMake(self.view.center.x, self.view.center.y + targetPointOffset)

        UIView.animateWithDuration(0.2, animations:  {
            self.view.center = adjustedViewFrameCenter
        })
    }

    func returnViewToInitialFrame()
    {
        var initialViewRect: CGRect = CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)

        if (!CGRectEqualToRect(initialViewRect, self.view.frame))
        {
            UIView.animateWithDuration(0.2, animations: {
                self.view.frame = initialViewRect
            });
        }
    }

    func textViewDidBeginEditing(textView: UITextView) {
        //
        print("text view did begin editing\n")
        //
        if(self.keyboardIsShowing)
        {
            self.arrangeViewOffsetFromKeyboard()
        }
    }

    func textViewDidChange(textView: UITextView) {
        print("text view did change\n")
        let textViewFixedWidth: CGFloat = self.textView.frame.size.width
        let newSize: CGSize = self.textView.sizeThatFits(CGSizeMake(textViewFixedWidth, CGFloat(MAXFLOAT)))
        var newFrame: CGRect = self.textView.frame
        //
        var textViewYPosition = self.textView.frame.origin.y
        var heightDifference = self.textView.frame.height - newSize.height
        //
        if (abs(heightDifference) > 5) {
            newFrame.size = CGSizeMake(fmax(newSize.width, textViewFixedWidth), newSize.height)
            newFrame.offset(dx: 0.0, dy: heightDifference)
            //
            updateParentView(heightDifference: heightDifference)
        }
        self.textView.frame = newFrame
    }

    func updateParentView(#heightDifference: CGFloat) {
        //
        var newContainerViewFrame: CGRect = self.commentView.frame
        //
        var containerViewHeight = self.commentView.frame.size.height
        print("container view height: \(containerViewHeight)\n")
        //
        var newContainerViewHeight = containerViewHeight - heightDifference
        print("new container view height: \(newContainerViewHeight)\n")
        //
        var containerViewHeightDifference = containerViewHeight - newContainerViewHeight
        print("container view height difference: \(containerViewHeightDifference)\n")
        //
        newContainerViewFrame.size = CGSizeMake(self.commentView.frame.size.width, newContainerViewHeight)
        //
        newContainerViewFrame.offset(dx: 0.0, dy: containerViewHeightDifference)
        //
        // self.commentView.frame = newContainerViewFrame
    }

    func textViewDidEndEditing(textView: UITextView) {
        //
        print("text view did end editing\n")
        //
        textView.resignFirstResponder()
    }

}
like image 344
coniferous Avatar asked Jan 25 '15 22:01

coniferous


Video Answer


2 Answers

I have a really simple answer, I hope it can help. What I have is pretty simple and doesn't invlove code. I did all by constraints. Here there are a pair of images to help me expain:

This is what I have

enter image description here

This is how it really looks like

enter image description here

It's crucial that the TextView has this property unchecked in property inspector:

enter image description here

Then you simple set the top, leading, trailing and bottom for each view and set no height to any of them. Everything will grow when typing along with it's parent views! :)

like image 183
xavi.pedrals Avatar answered Oct 12 '22 08:10

xavi.pedrals


This is what worked for me. In my case, I have the text view below a table view. So, as the text view grows in height, the parent view isn't actually what needs to change - the view above the text view is what needs to resize (for me it was the table view). So, here is what I implemented in the updateParentView function.

func updateParentView(heightDifference: CGFloat) {
    //
    var newContainerViewFrame: CGRect = self.commentTableView.frame
    //
    let containerViewHeight = self.commentTableView.frame.size.height
    print("container view height: \(containerViewHeight)\n")
    //
    let newContainerViewHeight = containerViewHeight + heightDifference
    print("new container view height: \(newContainerViewHeight)\n")
    //
    let containerViewHeightDifference = containerViewHeight - newContainerViewHeight
    print("container view height difference: \(containerViewHeightDifference)\n")
    //
    newContainerViewFrame.size = CGSizeMake(self.commentTableView.frame.size.width, newContainerViewHeight)
    //
    newContainerViewFrame.origin.y - containerViewHeightDifference
    //
    self.commentTableView.frame = newContainerViewFrame
}

Now, as the text view increases in height, the table view "slides up" per newContainerViewFrame.origin.y - containerViewHeightDifference. Check out the screenshot below.

Example Screenshot

like image 27
Jakoby Avatar answered Oct 12 '22 08:10

Jakoby