How to get the content Height of dynamically changing Text in textview? - ios

I have a dynamically changing text in TextView.I could not be able to get the content Height of TextView.
Here is what i tried.
let height = self.tvComment.contentSize.height
print("height",height)
let contentSizeComment = self.tvComment.sizeThatFits(self.tvComment.bounds.size)
print("height",contentSizeComment)
Why it's not getting the content height of TextView?
Hope you understand my problem.
Thanks in Advance

Usethis method to get the height -
func heightForString(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.size.height
}

in textdidchange you can use this code,in order to resize when textchange
//approxi should be the width of your textview
let approxi = view.frame.width - 90
//size is the max width and height of textview,1000 can be what ever you want
let size = CGSize(width: approxi, height: 1000)
//dont forget to put your font and size
//chey is the text of thetext view
let attributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 15)]
let estim = NSString(string: chey).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
//estim is height
above it the first method,second method will come in edit
second method is
func pva() {
//what was the name of my textfield
let fixedwidth = what.frame.size.width - 40
let newsize = what.contentSize.height
self.hrightext.constant = newsize
self.view.layoutIfNeeded()
}
note: both are tested and works in swift4

Your just write code in below delegate of UITextView:-
func textViewDidChange(_ textView: UITextView!) {
let height = self.tvComment.contentSize.height
print("height",height)
let contentSizeComment = self.tvComment.sizeThatFits(self.tvComment.bounds.size)
print("height",contentSizeComment)
}
I hope it help you,
Thank you.

Related

get height of dynamic textViews in tableView without using automatic dimensions using swift

I want to calculate the height of my textView's in a tableView dynamically to use in heightForRowAt. I DO NOT want to use automatic dimensions as it often messes up my scrolling in containerViews.
Presently I am instantiating a textView for every cell, adding the text and getting the height using:
var textViewForCellHeight = UITextView()
textViewForCellHeight.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
textViewForCellHeight.frame = CGRect(x: 0, y: 0, width: self.tableView.frame.size.width - cellHorizontalPadding - tableView.safeAreaInsets.left - tableView.safeAreaInsets.right, height: 0)
textViewForCellHeight.text = myString
textViewForCellHeight.sizeToFit()
return textViewForCellHeight.frame.size.height
Using this in heightForRowAt works fine and gives the correct height for the cell, but it expensive and slows down the tableView considerably. Is there a more efficient way to get the height of the tableView cell's dynamically with a textView?
You can simply pass your string in this function and you will get dynamic height according to your string.
func calculateHeight(inString:String) -> CGFloat
{
let messageString = input.text
let attributes : [NSAttributedStringKey : Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue) : UIFont.systemFont(ofSize: 15.0)]
let attributedString : NSAttributedString = NSAttributedString(string: messageString!, attributes: attributes)
let rect : CGRect = attributedString.boundingRect(with: CGSize(width: 222.0, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)
let requredSize:CGRect = rect
return requiredSize.height
}
Try this code:
func cellHeight(withTxt string: String) -> Float {
let textRect: CGRect = string.boundingRect(with: CGSize(width: self.view.frame.width/* Preferred textView Width */, height: CGFloat(MAXFLOAT)), options: ([.usesLineFragmentOrigin, .usesFontLeading]), attributes: [.font: UIFont(name: "Helvetica Neue", size: 17)!], context: nil)
let requiredSize: CGSize = textRect.size
//finally u return your height
return Float(requiredSize.height)
}

UITextview write in Text Center Alignment , swift

I have one Text Editor when I tap to Bold Button
I can write in Bold here is code
txtEditor.typingAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.black/, NSAttributedStringKey.font.rawValue: UIFont.boldSystemFont(ofSize: (txtEditor.font?.pointSize)!)]
I want to have one button when I tap to Button (The Line who I write) I need to in Centre Text Center Alignment and not other Line before
here is code
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = .center
but after how will to add this 2 line code in UITextview for typing in Centre Alignment ?
Try this.
extension UITextView {
func centerText() {
self.textAlignment = .center
let fittingSize = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
let size = sizeThatFits(fittingSize)
let topOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(1, topOffset)
contentOffset.y = -positiveTopOffset
}
}
use like this
#IBAction func btnClick(_ sender: Any) {
textView.centerText()
}
Swift 4+
func textViewDidChange(_ textView: UITextView) { textView.textAlignment = .center }

UITextView that starts scrolling when text reached N lines

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

How can I make a TextField width adapt to his content?

Is there any option that make a TextField adapt to his content?
There is a way to do it manually by adjusting the frame of the textview when a change in it occurs.
var text: String = "Some text is just here..."
let size: CGSize = text.size(attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 14.0)])
^The code will give you the size needed for the text to be fully displayed and you can resize you textView according to it. //be aware there might be some paddings inside the textview
extension String {
func heightWithConstrainedWidth(width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.height
}
}
^If you need dynamic height (multi-lines) constraining the width will help you with the task.
I'm not completely sure what you are trying to accomplish, but I hope this helps a little.
Create a oultet for height constraint of textview. After:
textView.delegate = self
textView.isScrollEnabled = false
func textViewDidChange(_ textView: UITextView) {
let fixedWidth = textView.frame.size.width
textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var newFrame = textView.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
heightTextview.constant = newFrame.size.height //update constraint constant with new height
}
textView will change height for fit multiple line content. It works well

Swift: how to get the correct String size

I want to calculate the size of a string, to resize a UILabel. I used three different ways to calculate the size, to be exact, two ways. But I got three different results, and totally confused.
The most confusing thing is that I created a UILabel and use sizeToFit() to get the size. then I use the size to create a real UILabel and display it, but the label is truncated. Then I use sizeToFit() again to adjust the real UILabel, and the size is larger.
I doubted if it's caused by scale differences. But it is still three results on different simulators/devices.
Here's my code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let items = ["connected devices", "join session", "start host"]
let font = UIFont.systemFontOfSize(16)
var i = 0
for item in items {
let size = item.size(font: font)
print("\(size)")
let attriSize = item.sizeWithAttributes([NSFontAttributeName:font])
print("attriSize\(attriSize)")
let label = UILabel(frame: CGRect(origin: CGPoint(x: 50, y: 50 + i*50), size: size))
label.text = item
label.backgroundColor = UIColor.redColor()
label.sizeToFit()
print("\(label.bounds.size)")
view.addSubview(label)
++i
print("\n")
}
}
}
extension String {
func size(font font: UIFont) -> CGSize {
let label = UILabel(frame: CGRectZero)
label.text = self
label.font = font
label.sizeToFit()
let size = label.bounds.size
return size
}
}
and the results are
(137.333333333333, 19.3333333333333)
attriSize(137.0859375, 19.09375)
(144.666666666667, 20.3333333333333)
(84.3333333333333, 19.3333333333333)
attriSize(84.265625, 19.09375)
(89.0, 20.3333333333333)
(70.0, 19.3333333333333)
attriSize(69.765625, 19.09375)
(73.6666666666667, 20.3333333333333)
I really want to know what's wrong with sizeToFit(). Any help is appreciated.
Hi it is working example that can help you :
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;

Resources