0
votes

I have set up a subclass of UITextView which expands and shrinks to fit the text as the user types, called FlexibleText. I also have a Pinch Gesture Recognizer on this text view allowing users to scale it up and down.

However, when I pinch to scale the text view down, then try to edit it again, after typing any character the UITextContainerView scales down inside the text view, cutting off some of the text.

I'd be really grateful for any help in figuring this out! Here is my code:

import UIKit

class ViewController: UIViewController, UITextViewDelegate, UIGestureRecognizerDelegate {

class FlexibleText: UITextView {
    var horizontalConstraint: NSLayoutConstraint?
    var verticalConstraint: NSLayoutConstraint?

    var widthConstraint: NSLayoutConstraint?
    var heightConstraint: NSLayoutConstraint?
}

var currentTextView = FlexibleText()

var screenWidth = UIScreen.main.bounds.width
var screenHeight = UIScreen.main.bounds.height


override func viewDidLoad() {
    super.viewDidLoad()

    //add close keyboard recognizer
    let closeKeyboardRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    view.addGestureRecognizer(closeKeyboardRecognizer)

    let text1 = FlexibleText()
    text1.text = "your text"
    text1.font = UIFont.systemFont(ofSize: 40)
    text1.backgroundColor = UIColor.yellow
    text1.frame = CGRect(x: 50, y: 100, width: 250, height: 100)
    text1.isScrollEnabled = false
    text1.delegate = self
    text1.textAlignment = .center
    view.addSubview(text1)

    // layout
    text1.translatesAutoresizingMaskIntoConstraints = false

    text1.horizontalConstraint = text1.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0)
    text1.horizontalConstraint?.isActive = true

    text1.verticalConstraint = text1.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
    text1.verticalConstraint?.isActive = true

    text1.widthConstraint = text1.widthAnchor.constraint(equalToConstant: 250)
    text1.widthConstraint?.isActive = true
    text1.heightConstraint = text1.heightAnchor.constraint(equalToConstant: 100)
    text1.heightConstraint?.isActive = true

    adjustTextViewHeight(text1)
    currentTextView = text1

    //add pinch gesture
    let pinchGesture = UIPinchGestureRecognizer(target: self, action:#selector(pinchRecognized))
    pinchGesture.delegate = self
    text1.addGestureRecognizer(pinchGesture)

}


// flexible functions
func textViewDidChange(_ textView: UITextView) {
    adjustTextViewHeight(textView)
}

func adjustTextViewHeight(_ textView: UITextView) {

    let newSize = textView.sizeThatFits(CGSize(width: screenWidth, height: CGFloat.greatestFiniteMagnitude))

    if let currentView = textView as? FlexibleText {

        if newSize.width <= screenWidth {
            currentView.widthConstraint?.constant = newSize.width
        } else if newSize.width > screenWidth {
            currentView.widthConstraint?.constant = screenWidth
        }

        currentView.heightConstraint?.constant = newSize.height
    }

    self.view.layoutIfNeeded()
}



@objc func dismissKeyboard() {
    view.endEditing(true)
}


//pinch gesture
@objc func pinchRecognized(recognizer: UIPinchGestureRecognizer) {

    if let view = recognizer.view as? FlexibleText {

        if recognizer.state == .changed {

            view.transform = view.transform.scaledBy(x: recognizer.scale, y: recognizer.scale)

        } else if recognizer.state == .ended {
            view.font = UIFont.systemFont(ofSize: 40 * recognizer.scale)
        }

        adjustTextViewHeight(view)
        recognizer.scale = 1.0

    }

}



}

Here is an image of before scaling down:

example

and after:

example

And a screenshot of the view hierarchy:

example

Thanks!

2

2 Answers

0
votes

I managed to solve this with the help of this answer: iOS: Scaling UITextView with pinching?

It involves only changing the font size on scale, and then adjusting the text view size to that. Here is my working code:

import UIKit

class ViewController: UIViewController, UITextViewDelegate, UIGestureRecognizerDelegate {

class FlexibleText: UITextView {
    var horizontalConstraint: NSLayoutConstraint?
    var verticalConstraint: NSLayoutConstraint?

    var widthConstraint: NSLayoutConstraint?
    var heightConstraint: NSLayoutConstraint?
}

var currentTextView = FlexibleText()

var screenWidth = UIScreen.main.bounds.width
var screenHeight = UIScreen.main.bounds.height


override func viewDidLoad() {
    super.viewDidLoad()

    //add close keyboard recognizer
    let closeKeyboardRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    view.addGestureRecognizer(closeKeyboardRecognizer)

    let text1 = FlexibleText()
    text1.text = "your text"
    text1.font = UIFont.systemFont(ofSize: 40)
    text1.backgroundColor = UIColor.yellow
    text1.frame = CGRect(x: 50, y: 100, width: 250, height: 100)
    text1.isScrollEnabled = false
    text1.delegate = self
    text1.textAlignment = .center
    view.addSubview(text1)


    // layout
    text1.translatesAutoresizingMaskIntoConstraints = false

    text1.horizontalConstraint = text1.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0)
    text1.horizontalConstraint?.isActive = true

    text1.verticalConstraint = text1.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
    text1.verticalConstraint?.isActive = true

    text1.widthConstraint = text1.widthAnchor.constraint(equalToConstant: 250)
    text1.widthConstraint?.isActive = true
    text1.heightConstraint = text1.heightAnchor.constraint(equalToConstant: 100)
    text1.heightConstraint?.isActive = true


    adjustTextViewSize(text1)
    currentTextView = text1

    //add pinch gesture
    let pinchGesture = UIPinchGestureRecognizer(target: self, action:#selector(pinchRecognized))
    pinchGesture.delegate = self
    text1.addGestureRecognizer(pinchGesture)



}


// flexible functions
func textViewDidChange(_ textView: UITextView) {
    adjustTextViewSize(textView)
}



func adjustTextViewSize(_ textView: UITextView) {

    let newSize = textView.sizeThatFits(CGSize(width: screenWidth, height: CGFloat.greatestFiniteMagnitude))

    textView.frame = CGRect(x: (textView.frame.minX), y: (textView.frame.minY), width: newSize.width, height: newSize.height)

    if let currentView = textView as? FlexibleText {

        if newSize.width <= screenWidth {
            currentView.widthConstraint?.constant = newSize.width
        } else if newSize.width > screenWidth {
            currentView.widthConstraint?.constant = screenWidth
        }

        currentView.heightConstraint?.constant = newSize.height

    }

    self.view.layoutIfNeeded()

}



@objc func dismissKeyboard() {
    view.endEditing(true)
}


//pinch gesture
@objc func pinchRecognized(recognizer: UIPinchGestureRecognizer) {

    let scale:CGFloat = recognizer.scale

    guard let textView = recognizer.view as? FlexibleText else { return }

    textView.font = UIFont(name: textView.font!.fontName, size: textView.font!.pointSize*scale)

    adjustTextViewSize(textView)

    recognizer.scale = 1.0

}



}
-1
votes

add this code

currentTextView.contentInsetAdjustmentBehavior = UIScrollView.ContentInsetAdjustmentBehavior.never' into your method 'viewDidLoad()