I am using the following code to dynamically adjust the height of the containerView which contains my UITextView
func textViewDidChange(textView: UITextView) {
let amountOfLinesToBeShown:CGFloat = 6
let maxHeight:CGFloat = textView.font!.lineHeight * amountOfLinesToBeShown
if ((textView.contentSize.height / textView.font!.lineHeight) < 6) {
topConstraint?.constant = -textView.sizeThatFits(CGSizeMake(textView.frame.size.width, maxHeight)).height - keyboardFrameSize!.height
containerView.layoutIfNeeded()
containerView.updateConstraints()
}
}
The problem is, when I am typing, it appears like this:
and the desired effect is this:
The top answer from this post solves this issue. How do I size a UITextView to its content?
The code below is not mine, it is from the answer linked above (simply posting for other's convenience):
let fixedWidth = textView.frame.size.width
textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height:CGFloat.max))
var newFrame = textView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
textView.frame = newFrame;
The code below might be the solution for this problem you got.
func textViewDidChange(textView: UITextView) {
var newFrame = textView.frame
var minHeight = 40 // ENTER THE MIN HEIGHT OR THE INITIAL HEIGHT OF THE TEXTVIEW
var maxHeight = 100 // ENTER THE MAX HEIGHT YOU WANT
newFrame.size = textView.sizeThatFits(CGSizeMake(newFrame.size.width, maxHeight))
if newFrame.size.height > minHeight && newFrame.size.height < maxHeight {
// Change the origin.y value which is 10 to your desired margin for top.
textView.frame = CGRectMake(0, 10, textView.frame.size.width, newFrame.size.height)
}
}
Create a function and add this in your viewDidLoad method, try with:
self.addSubview(containerView)
containerView.addSubview(textView)
containerView.bottomAnchor.constraintEqualToAnchor(self.bottomAnchor).active=true
containerView.leftAnchor.constraintEqualToAnchor(self.leftAnchor).active=true
textView.topAnchor.constraintEqualToAnchor(containerView.topAnchor, constant: 3).active=true
textView.leftAnchor.constraintEqualToAnchor(containerView.leftAnchor, constant: 3).active=true
textView.widthAnchor.constraintEqualToAnchor(containerView.widthAnchor).active=true
textView.heightAnchor.constraintEqualToAnchor(containerView.heightAnchor).active=true
use textview textContainerInset method for achieving what u want
//insets are top, left, bottom, top..
tv.textContainerInset = UIEdgeInsetsMake(0,0,0,0);
after setting this method,when textview line starts, increase height of textview for finding the textview next line start,
use method:- TextViewDidChange
Related
I have tried 2 more methods. But those are not giving me the correct solution.
If i tried this one
func textViewDidChange(_ textView: UITextView) {
self.comments.translatesAutoresizingMaskIntoConstraints = true
self.comments.sizeToFit()
self.comments.isScrollEnabled = false
}
i can only type a one letter per a line.
If i tried this one
func textViewDidChange(_ textView: UITextView) {
self.comments.translatesAutoresizingMaskIntoConstraints = true
self.comments.isScrollEnabled = false
let fixedWidth = passedOut.frame.size.width
let newSize = comments.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
comments.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
}
Its working.
But at the viewDidLoad stage, the width of textview is certain less than which i constraints to the textview. But i gave the leading, trailing , height as same as passedOut textfield to that textview.
If i start typing in textview, the width of textview will become exact size which i want.
So pls suggest me what mistake i made?
Assign a height constraint to the text view
Use the following method to change the height:
func textViewDidChange(_ textView: UITextView) {
let size = textView.bounds.size
let newSize = textView.sizeThatFits(
CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude)
)
if size.height != newSize.height {
self.userMessageTextViewHeightConstraint.constant = newSize.height
textView.layoutIfNeeded()
}
}
You can achieve this behavior by doing 2 things in textview
Disable scrolling in textview
Assign the following constraints to textview
a) leading
b) trailing
c) top
d) height >= 30 ,assuming 30 is the minimum height of your textview.
Now when your text will grow textview will grow with it.
I have got a text view and a view like this
let lb = UITextView()
let view = UIView()
background_img_view.addSubview(about_txt)
lb doesn't have fixed height,it can be 30 or 300px,how can i use sizeThatFits to make background_img_view's height depend on lb's?
Try this:
// Get the width you want to fit
let fixedWidth = textView.frame.size.width
// Calculate the biggest size that fixes in the given CGSize
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
// Set the textView's size to be whatever is bigger: The fitted width or the fixedWidth
textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
// Make the "background_img_view" height match the textView's height
background_img_view.frame.size.height = textView.frame.size.height
I'm start implementing text input to a chat app and wondering that is standard behavior of a UITextView with scroll enabled absolutely does not meet expectations.
I want just it is done in chats like WhatsApp. When text reached N, 5 for example lines, scroll bar appear and text container starts scrolling. I wrote code like this, but it doesn't work.
As i think needs to count rows in text container and make content insets, or something like this.
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = myTextView.frame.size.width
myTextView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = myTextView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var newFrame = myTextView.frame
let oldFrame = myTextView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
myTextView.frame = newFrame
let shift = oldFrame.height - newFrame.height
textView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: shift, right: 0)
textView.scrollIndicatorInsets = textView.contentInset
textView.scrollRangeToVisible(textView.selectedRange)
}
And myTextView is specified as:
let myTextView : UITextView = {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isScrollEnabled = false
textView.textContainer.maximumNumberOfLines = 5
textView.textContainer.lineBreakMode = .byWordWrapping
textView.inputAccessoryView = UIView()
return textView
}()
Not based on number of lines, but on a user defined height. You'll find your answer here:
https://stackoverflow.com/a/51235517/10115072
If you want this behaviour to happen is simple:
Create a UIView having UITextView inside
Create a height constraint in UIView priority 1000 of less than or equal your MAX_HEIGHT and also greater than or equal you MIN_HEIGHT
Create a height constraint in you TextView priority 999 equal to your MIN_HEIGHT
Then add this code to your controller
Code:
class YourViewController: KUIViewController {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
textView.isScrollEnabled = true
}
}
extension YourViewController: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
let size = CGSize(width: view.frame.width, height: .infinity)
let estimatedSize = textView.sizeThatFits(size)
textView.constraints.forEach { (constraint) in
if constraint.firstAttribute == .height {
constraint.constant = estimatedSize.height
}
}
}
}
This has the same behaviour as WhatsApp textView
I have a swift app and there I have a view with embedded textView.
It looks like this:
My view is below the map, hence it has constraints:
- top space 0 to MapView
- trailing and leading 0
- bottom: 49 to superview (it's embedded in tab controller so with value 49 it's exactly above the tab controls)
The textView has standard constraints:
- leading, bottom, top 4 to view border
- trailing 8 to button
- height 30
when I run the app everything is fine, I see the map and I see the textView below it. When I start typing something in the textView it goes up with the keyboard (thanks to this:
func keyboardWillChangeFrame(notification: NSNotification) {
let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
if(isKeyboardShown == true)
{
bottomConstraint.constant = CGRectGetHeight(view.bounds) - endFrame.origin.y+49
self.view.layoutIfNeeded()
isKeyboardShown = false
} else {
//scrollToBottom()
bottomConstraint.constant = CGRectGetHeight(view.bounds) - endFrame.origin.y
self.view.layoutIfNeeded()
isKeyboardShown = true
}
}
, where bottomConstraint is an IBOutlet to the bottom constraint (=0) of the textView. Anyway, I added this method:
func textViewDidChange(textView: UITextView) {
let fixedWidth = textView.frame.size.width
textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
var newFrame = textView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
textView.frame = newFrame
}
and I expected the textView to change its size. It's happening, but the textView expands to the bottom - I mean when user starts writing more than one line the textView goes partially under keyboard, instead of covering more and more part of the map. What is more, while going down, the textView goes over the gray view - so the view itself does not expand.
How can I fix it so that the textView and the view grow up covering more and more map with every new line? I don't want it to hide partially under keyboard.
I'm trying to make a text messaging text box that makes the text view bigger and the UIView (in which the text view is contained) bigger as well. I'm working with constraints. When I reach a certain height, I want it to scroll and stop increasing the heights of the container. I've tried all ways possible, including using this forum (How do I size a UITextView to its content?).
One problem occurs when I type it in, once I reach a certain height, it starts typing out of sight below.
func textViewDidChange(textView: UITextView) {
let fixedWidth = self.chatTextField.frame.size.width
self.chatTextField.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
let newSize = self.chatTextField.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
var newFrame = self.chatTextField.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
print(textViewAnchorHeight?.constant)
if textView.contentSize.height <= self.chatTextFieldHeightAnchor?.constant {
textView.scrollEnabled = false
self.chatTextField.frame = newFrame
//self.chatTextFieldHeightAnchor?.constant = newSize.height
self.textViewAnchorHeight?.constant = newSize.height
} else {
textView.scrollEnabled = true
self.automaticallyAdjustsScrollViewInsets = true
print("here")
}
What can I do to make the perfect text view?
You can use the code below to achive that dynamic resize. You might want to change differenceOfHeightvalue to your liking.
func textViewDidChange(textView: UITextView) {
var newFrame = textView.frame
var minHeight = 40 // ENTER THE MIN HEIGHT OR THE INITIAL HEIGHT OF THE TEXTVIEW
var maxHeight = 100 // ENTER THE MAX HEIGHT YOU WANT
newFrame.size = textView.sizeThatFits(CGSizeMake(newFrame.size.width, maxHeight))
if newFrame.size.height > minHeight && newFrame.size.height < maxHeight {
let differenceOfHeight = newFrame.size.height - textView.frame.size.height
holderView.frame = CGRectMake(holderView.frame.origin.x, holderView.frame.origin.y - differenceOfHeight, holderView.frame.size.width, newFrame.size.height)
textView.frame = newFrame
}
}