dynamically displaying table cells height with boundRectWIthSize - ios

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);

Related

Get the content height of a UITextView

I use this open source library called ReadMoreTextView to display a bunch of text. The library enables me to toggle between displaying an excerpt of the text and showing the full length content (the button is a normal UIButton added by me, not the library).
This works as expected.
My problem arises when I have to display a smaller amount of text. If I add some content that doesn't exceed the height of the UITextView, I want to hide the more/less toggle button. So I thought of taking the full content height and if only it's larger than the text view's height, show the toggle button.
In the above example, I aded a long couple of paragraphs that exceeds the text view bounds. The text view's height comes up as 128. But the content height also returns 128. There's a library specific method called boundingRectForCharacterRange which is supposed to return the content height also returns a wrong value (100).
print("TEXTVIEW HEIGHT: \(textView.bounds.height)") // 128
print("CONTENT HEIGHT: \(textView.contentSize.height)") // 128
let rect = textView.layoutManager.boundingRectForCharacterRange(range: NSRange(location: 0, length: textView.text.count), inTextContainer: textView.textContainer)
print("TEXT HEIGHT: \(rect.height)") // 100
I opened an issue at the library's Github page but the owner asked to ask it here.
Why does the content height return a wrong value?
Here is the project I'm using in the above example by the way.
You can simply use following method to get the content size:
let contentSize = self.textView.sizeThatFits(self.textView.bounds.size)
Then update the textview frame accordingly:
self.textView.frame = CGRect(width: contentSize.width, height: contentSize.height)

IOS Section Footer Cell Height based on Content

i need to create a custom footer for a section within a table view. The footer contains a text (label) and a button underneath it.
The problem is that the text has a different length in different languages. How can I create the footer with a dynamic height based on the content from the label?
Thx!
You can determine the height of the footer view by calculating the estimated size of the label according to the text inside of it, adding the height of the button and adding perhaps another small value for padding.
Here's a Swift example:
let theLabelFont = UIFont.systemFontOfSize(FONTSIZE)
let labelRect = (yourLabelText as NSString).boundingRectWithSize(CGSizeMake(LABEL_WIDTH, CGFloat.max), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName:theLabelFont], context: nil)
let footerHeight: CGFloat = labelRect.height + (YOUR_BUTTON).frame.height + somePaddingValue
Then simply return it in the heightForFooterInSection: method.

How to get UILabel to resize better?

I am trying to make my multiline UILabel as small as possible with given max-width, but the sizeToFit() and sizeThatFits(_,_) methods aren't giving the results I want.
Take a look at this image:
The red rectangle represents the width that I pass in sizeThatFits (while height being Max). Obviously, as you can see, this method does in fact return a size that fits, but it does not give me the smallest size possible, which I want.
Let's say I specified max-width: 300. This actual result is giving me a size of ca. 280*50.
As you can see in the image, the text is now written like this:
Here is some text that is supposed to
align nicely
What I want to achieve is this:
Here is some text that is
supposed to align nicely
This result would've had the same height, but a much smaller width, e.g 200*50
I realize that it's difficult to define "smallest size possible", as it could return this:
Here
is
some
text
that
...
Or even just a single letter per line. But given that sizeThatFits returns this, with a given width and height, why doesn't it return my wanted result, which is the same height, but with smaller width. Why isn't the smallest fit returned? Does a function like this exist?
Sti,
You can try this buddy :) I have been using it and seems to do a pretty good job :)
CGRect rect = [yourText boundingRectWithSize:CGSizeMake(maxWidth_you_Can_afford, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:16]}
context:nil];
The rect after executing will have the minimum width and height that will be required to render the text :)
Once you have the frame now you can set the same for your label and set the text as well :)
I have used it in chat bubble :) and it works well :)
Happy coding :)
I made my own solution, which works pretty well:
private func calculateWantedSize(label:UILabel)->CGSize{
var lastAcceptableWidth = label.bounds.width
let currentHeight = label.sizeThatFits(CGSize(width: label.bounds.width, height: CGFloat.max)).height
var tempHeight = currentHeight
while(tempHeight == currentHeight){
let newWidth = lastAcceptableWidth - 1
tempHeight = label.sizeThatFits(CGSize(width: newWidth, height: CGFloat.max)).height
if tempHeight == currentHeight{
lastAcceptableWidth = newWidth
}
}
return CGSize(width: lastAcceptableWidth, height: label.bounds.height)
}
Here I'm sending my label to a function which first calculates the current width and height of the label, then loops through width-1 and checks the resulting height until the height is changed. The height will change when the width is so low that it needs a new line. When this happens, I return the last valid width which still needed the same height as original.
This is perfect for my problem, using attributed text etc.
Of course, when using this, be sure to do some checking before calling. I don't know what will happen if you use this function when the label has a single word, or a single letter, or no text at all. I have only tested this for the cases I know will happen with this app, and it works well.

How to get content height of UITextView with word wrapping

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

elipsis dots after UITextfield for secured text entry

I have multiple uitextfields setup and they are all connected with IBOutlets. I have one textfield that is a password and I have the 'Secure text Entry' selected. when I have this check I get this
Any ideas why this happens? If i deselect the secured entry the textfield rises fine depending on the size of the password with no ellipsis dots.
It does not matter how long the password is. Same thing.
If i don't have the security text selected it works fine
Any idea why? It can be a width issue because it does autosize. But why does the 'secure text entry' cause the issue?
I have faced the same problem. I think it is a bug of UITextfield. It calculates size for the text but not for the secure text(dots). I have the problem when the text includes slim characters like 1, l etc...
As workaround I have subclassed the UITextfield class and overridden intrinsicContentSize function. You might need to adjust letter spacing. I couldn't find how to get it dynamically depending on font.
override var intrinsicContentSize: CGSize {
let size = super.intrinsicContentSize
if !self.isSecureTextEntry {
return size
}
var width = size.width
if let font = self.font,
let charCount = self.text?.count {
width = "•".size(withAttributes: [NSAttributedString.Key.font : font]).width * CGFloat(charCount)
width += (CGFloat(charCount)+1) * 4.5 // this magic number is for letter spacing
}
return CGSize(width: width, height: size.height)
}

Resources