How to get content height of UITextView with word wrapping - ios

I am trying to get the content height of an UITextView for calculating the bottom position of it (y position + height).
I can get the y position just fine with
travelDescriptionTextView.frame.origin.y
and need to determinate the height. All over the internet it says to get the content height with:
let contentSize = self.travelDescriptionTextView.sizeThatFits(self.travelDescriptionTextView.bounds.size)
let height = contentSize.height
but this technique doesn't work when height is resized (extended) by word wrapping, that is, if a sentence is wider than the width of the text box and the textbox creates a new line automatically. The above technique for getting content height only get the height right if there is no word wrapping, or else the height is excluding the extra word wrapping lines causing the content height to be shorter than the actual content height.
So how do I get the content height of a UITextView containing word wrapping height resizes?

Try like as follows,
let textViewComputedHeight = textView.contentSize.height - textView.contentInset.top - textView.contentInset.bottom

Thanks to RDC for the link. The working solution is:
self.travelDescriptionTextView.sizeToFit()
self.travelDescriptionTextView.layoutIfNeeded()
let contentSize = self.travelDescriptionTextView.sizeThatFits(self.travelDescriptionTextView.bounds.size)
let textViewHeight = contentSize.height

Related

UILabel find height that fits width

I have a UILabel that I need to have a specific text size and frame width (matching the screen width). I want to be able to set the label's height to the minimum height that will fit all of the label's text without cutting it off.
I've tried the following:
let label = UILabel()
label.text = longText
label.numberOfLines = 0
label.sizeToFit()
But this won't work if longText is something like "This string is really long, longer than the screen width" as sizeToFit puts that entire string on one line and the text gets cut off with ... when it reaches the screen width.
I then tried setting the label's width to match the screen width after calling sizeToFit. This lets the line wrap but doesn't adjust the label's height, so the string is still cut off after the first line.
Also, setting label.adjustsFontSizeToFitWidth = true won't work because I need the label to have a specific font size.
What I'd like to have is some kind of function like label.minimumHeightForWidth: where I can pass UIScreen.main.bounds.width as the width parameter and get a height that will fit the label's text on as many lines as needed with the given width parameter. Is it possible to do something like this?
You can try
let fixedWidth = UIScreen.main.bounds.width
let newSize = lbl.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
lbl.size = CGSize(width:fixedWidth, height: newSize.height)

Prevent UITextView from offsetting its text container

I am tying to modify the height of a UITextView dynamically (up to a max height) while the user enters text. I am experiencing a very strange behavior when there are an even number of lines in the text view.
I am using autolayout and the text view has a height constraint. I respond to calls to the text view's delegate (textViewDidChange(_:)), where I calculate and adjust the height constraint based on the contentSize.
Here is the code:
func textViewDidChange(_ textView: UITextView) {
let newHeight = textView.contentSize.height
let newConstraintConst = max(MinTextViewHeight, min(MaxTextViewHeight, newHeight))
self.textViewHeightConstraint.constant = newConstraintConst
}
This works well, it resizes the frame up to MaxTextViewHeight and then the text view can scroll. However, when there are an even number of lines in the text view, the text view adds a kind of offset to the bottom of its NSTextContainer, causing the top line to be cut off:
However, when there are odd lines the NSTextContainer is no longer offset:
At first I thought it was somehow being controlled by the text view's textContainerInset but that is only used to pad the space inside the NSTextContainer, as setting it to .zero removes the space inside but does not affect the offset (and incidentally makes it even worse, as the top line almost completely disappears):
I have looked through the UITextView class reference and I don't see any property that would let me manipulate or even get the value of this offset.
As a workaround I am increasing the text container's top inset and removing the bottom inset:
textView.textContainerInset = UIEdgeInsetsMake(10, 0, 0, 0)
This works so far, but I arrived at a value of 10 by trial-and-error, and so far I've only tested it on a single device.
I am not interested in more hacky workarounds that require fragile, fixed values; I am trying to understand how this offset is being set and a proper way to fix it. I'm hoping that someone can provide some insight, thanks!
Just a speculation, but I think the problem is that the text view assumes that the height of itself does not change while calling textViewDidChange, so it scrolls when it thinks it has to, regardless of you changing its frame.
Not sure if you think my solution is too hacky, but this will stop it from scrolling when you don't want it. I simply pin the content offset to the top as long as the wanted content size is smaller than your max size.
Just add this:
func scrollViewDidScroll(scrollView: UIScrollView) {
if textView.contentSize.height <= MaxTextViewHeight && textView.contentOffset.y > 0.0 {
textView.contentOffset.y = 0.0;
}
}

Swift 4 - Editing label frame.size.height with negative number

So I have a label that I've made in Xcode's storyboard which I want to later edit in my code. I want it to simulate something like a vertical bar so I am editing its height by doing:
answerE.frame.size.height = -200
The problem comes from the negative number, I want the label to "grow" up so the height has to be negative from its original position... I have the line in code in a simple action on button press, but each time the line is executed the label moves "up" and eventually after 3-4 clicks is out of the screen.
I just want to edit its height, what is the correct way and what am I doing wrong?
My exact line in code is:
label.frame.size.height = -CGFloat(Double(x)/Double(y) * (200))
If you have added the label in storyboard, why not you use constraints to get the result.
Add leading, trailing , bottom and fixed height constraint and connect IBOutlet to height constraint. Change the constant value of height constraint at the event which you want to perform.
If I'm right, you want the label to gain height, keeping the same bottom edge, but the top edge moving up.
In order to do this, you want to change the frame.origin.y as you change the frame.size.height at the same amount, as its placement (and so top edge) is determined by its origin. So maybe make it zero height, place it where you want it in storyboard, and then when you want it to 'grow' by x:
label.frame.size.height = label.frame.height + x
label.frame.origin.y = label.frame.origin.y - x

iOS: `UICollectionview`, how to get a cell's `contentoffset` by it's `indexPath`

I'm using a UICollectionview with a circular layout. I'm trying to calculate the contentOffsetper item but with the circular layout the full contentsize does not seem match the content.
The collectionview's total contentSize = 780
The content offset of the last item = 397(?)
The content offset per item = 33(?)
Is there any way I can get the offset for an item by it's indexPath or at least the correct (397) value for the last item's in the collectionview? I got these values by testing and printing the contentoffset but I would like to calculate these numbers (33 and 397) by code without having to scroll.
So is there a way to calculate a cell's contentoffset(?) inside the collectionview by it's indexPath?
Thanks!
I found the problem, the contentsize of the scrollview is the size of the content + the size of the uicollectionview's frame. That was the reason the contentSize returned a larger size than the actual content was.
so:
(contentSizeX - collectionviews frame X) / cells = contentOffset per item
(780 - 383) / 12 => 33

dynamically displaying table cells height with boundRectWIthSize

Right now, I'm using the following code to display my table cell. It is displaying text properly. However, there are some texts which are too long, so I want to display the first 5 lines of the text and then if the user expands the cell, it will display the whole text. I'm stuck because I am not so familiar with the new method in ios 7, boundRectWithSize.
CGSize size = CGSizeMake(self.reviewComments.width,999);
CGSize textRect =[self.reviewComments.text boundingRectWithSize: size options: NSStringDrawingUsesLineFragmentOrigin
attributes: #{NSFontAttributeName:self.reviewComments.font} context: nil].size ;
float height = textRect.height;
self.reviewComments.height = height;
I tried:
if (height > 150) {
height = 150;
}
But this way just cuts off the text, even after when I expand it.
UPDATE/EDIT:
I want my cell so that it only displays maybe the first 5 lines of the text if it exceeds 5 lines. The entire text will appear if the cell is expanded.
Try this:
float height = ceilf(textRect.height);

Resources