How do I calculate the exact height of text using UIKit? - objective-c

I'm using -[NSString sizeWithFont] to get the text height. The character 't' is clearly taller than 'm', but -sizeWithFont returns the same height for both these strings. Here's the code:
UIFont* myFont = [UIFont fontWithName:#"Helvetica" size:1000.0];
NSString* myStr = #"m";
CGSize mySize = [myStr sizeWithFont:myFont];
With 'm' as shown, it returns {834, 1151}. With myStr = #"t" instead, it's {278, 1151}. The smaller width shows up as expected, but not the height.
Does some other function wrap the text tightly? I'm ideally looking for something equivalent to Android's Paint.getTextBounds().

The information you get back from this method is basically the line height for the font (i.e., it's the ascent plus the descent for the font you've chosen). It's not based on individual characters, it's based on specific font metrics. You can get most of the information about a font's metrics from the UIFont class (e.g., the method -ascender gives you the height of the ascender for the font). Mostly, you will be dealing with the total amount of vertical space needed to draw the glyphs with the heights ascenders and the lowest descenders for that font. There is no way to get information about individual glyphs from UIFont. If you need this information, you'll have to look at the CoreText framework, which gives you a lot more flexibility in how you draw and arrange glyphs but is far, far more complicated to use.
For more information on dealing with text in your app, please se the Drawing and Managing Text section of the Text, Web, and Editing Programming Guide. It is also a good launching point for most of the frameworks and classes you'll need to deal with whether you go the UIKit or the CoreText route.

Hmmm... I assume you're only going to be working with individual characters then. sizeWithFont, as noted above, returns the height of the largest character of that font as the text field is going to be that height no matter what you do. You would be able to get the LARGEST height values (UIFont's CGFloat capHeight) however it looks like you're going to be working with all kinds of text
I would take a look at the CoreText framework. Start here and read away. Inevitably you're going to end up with something along the lines of this:
CGFloat GetLineHeightForFont(CTFontRef iFont)
{
CGFloat lineHeight = 0.0;
check(iFont != NULL);
lineHeight += CTFontGetLeading(iFont);
return lineHeight;
}

Related

Constraints in iOS 8

I am creating a table header view with two UILabels. The constraints look like this:
The top UILabel is attached to the top, leading and trailing edges of the container. The bottom UILabel has the leading and trailing edges aligned to the top label, and the bottom edge to the bottom of the container. There is also a vertical spacing constraint between the two UILabels. All views translatesAutoresizingMaskIntoConstraints have been set to NO of course. BTW, the whole thing is made in code.
I calculate the height of the UIView by getting the intrinsic content size of each label and padding so that I can create the rect of the container view and add it to the UITableView. Like this:
-(float)calculateHeightwithMaxWidth:(float)maxWidth
{
float totalHeight = 0;
const float containerPadding = 30;
const float maxHeight = 1000;
maxWidth = maxWidth - containerPadding;
UIFont *nameFont = [UIFont fontWithName:#"AvenirNext-Regular" size:18];
UIFont *descriptionFont = [UIFont fontWithName:#"AvenirNext-Regular" size:13];
CGSize nameSize = [_productNameLabel.text gsSizeWithFont:nameFont
withMaximumSize:CGSizeMake(maxWidth, maxHeight)];
CGSize descriptionSize = [_productDescriptionLabel.text gsSizeWithFont:descriptionFont
withMaximumSize:CGSizeMake(maxWidth, maxHeight)];
totalHeight = nameSize.height + descriptionSize.height + containerPadding;
return totalHeight;
}
This code works perfectly in iOS 7 and has been working for several versions. Now that I'm testing in iOS 8 I get a crash with unsatisfying constraints. If I see the constraints of the view before calling layoutIfNeeded everything looks great, but after calling it I see two new constraints, which are the width and height constraints of the container view. I never created this constraints, and in iOS 7 never needed to.
Even after creating these constraints myself to fix this, I get even more errors trying to break them. Am I missing something? Did the logic for constraints change in iOS 8?
Thanks!
The problem is that you are asking for too much precision. You don't know exactly what height the auto layout system will give (you are just adding up some numbers that you think will give the same result), and so when you assign the header view a fixed height, if it doesn't match the system's own calculation perfectly, right down to the last decimal place, the constraints can't be satisfied. You should never have been doing it that way in the first place; you are mixing apples with oranges (manual calculation with the system's autolayout). The system may, for example, apply rounding of which you can know nothing (in order to keep the rects integral, etc.). Who knows what it does? I'm amazed that this ever worked.
You have two much better choices:
Wrap the pair of views in a container view (looks like you've done that) and just ask the container view for its systemLayoutSizeFittingSize. This tells you exactly what the system will do. In other words, instead of you calculating (which is hit or miss), ask the system to calculate.
Even better, allow yourself some slack: make one of the height spacer constraints an inequality or a lower priority, so that when you apply your fixed height that constraint has permission to grow or shrink.

UItextview not expanding with constraints as expected

I am working with interface builder to create a xib. This xib has a uiview that contains a uitextview. Both are supposed to resize as the text in the uitextview changes. The constraints look a lot like this:
The pink UITextView pushes on the blue superview. The blue uiView has a minimum width of 189 px and a trailing constraint of at least 8px.
For the most part this works. Really long sections of text resize the two views to the fullest extent allowed as intended and if there are only one or two words, the views stay small. However, the problem is when you have a short sentence.
In this case, the views only expand to about 189px, and the text moves to the second line even though there is space to expand.
Here is what it looks like when you only put a few words in:
and here is a fully expanded box:
I have tried to make the trailing constraint have a lower priority than the others, and I have tried modifying the content hugging and compression resistance properties in many ways without success.
How can I make the views expand so that they fit the text content with the fewest number of lines? There are no restrictions on height, only on width.
Any help would be appreciated!
Get the new size of the textView using this method
CGSize sz = [_textView.text sizeWithFont:_textView.font]
in case that didn't work very well with the height,get the width you just got from the preivous method and use in the next method to get the appropriate height you need
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width
{
UITextView *textView = [[UITextView alloc] init];
[textView performSelectorOnMainThread:#selector(setAttributedText:)
withObject:text
waitUntilDone:YES];
CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
The key is to set the preferredMaxLayoutWidth to something big (320px sounds good. Your right constraint is going to limit it anyways).
You can do that in your code as
[self.label setPreferredMaxLayoutWidth:320];
Or from the Interface Builder as follows:
This way you'll see the label expanding as expected:
Have you tried the solution presented in this post?
Dynamic expand UITextView on ios 7
I believe you have to set your UITextView to sizeToFit
[YourUITextView sizeToFit];

PDF creation and text formatting

Question about text formatting when creating a PDF programmatically on the iPhone.
I have a formatted NSString with Tabs (\t) in it. On the debugging output it looks perfect and fine, but when this strings is used to generate a PDF, the Tabs are gone and replaced by a single space.. Any idea?
( Tried a font like Courier, no luck, also the page boundary is big enough, there is more then enough room to display the text)
This is the code I use to make the PDF:
- (void)drawStuffInContext:(CGContextRef)ctx {
UIFont *font = [UIFont fontWithName:#"Arial" size:10];
CGRect textRect = CGRectInset(kPDFPageBounds, 36, 36);
[textHolder drawInRect:textRect withFont:font];
}
You're not very clear in describing what exactly you're doing.
But the first thing I would try is this:
Replace your tabs with spaces yourself -- use as many spaces for each tab as make you happy.
Then convert this new string/text to PDF.

DBLCDTempBlack only for some letters in UILabel

I am uising this code for marquee effect. i want digital clock like font so i gave font as
UIFont *lcdFont = [UIFont fontWithName:#"DBLCDTempBlack" size:60.0];
self.font = lcdFont ;
But i am getting this font only for some random characters.I am using only uppercase letters. I want i for all the characters in UILabel.
Why is it happening so.
It's nothing wrong with your code -- that font only has certain characters in it. (Why? Who knows.) For those it's missing, the OS automatically falls back to another font.
If you want to draw LCD-looking text using a broader character set, you'll need to find such a font elsewhere and bundle it in your app.

How to generate an end screen when two images collide?

how to generate an end screen when two images collide. I am making an app with a stickman you move with a very sensitive acceremeter. SO if it hits these spikes, (UIImages) it will generate the end screen. How do I make the app detect this collision and then generate an end screen.
I'm sure you know the rect of the two images because you need to draw them so you can use
bool CGRectIntersectsRect (
CGRect rect1,
CGRect rect2
);
It returns YES if the two rects have a shared point
The fact that you haven't declared any rects doesn't matter. You need rects for collision detection. I assume that you at least have x and y coordinates for the stickman and you should have some kind of idea of his height and width. Judging from the question title it seems like you're using images to draw the objects you want to check for collision, so you should know the height and width of the images you're using. If you don't have this info you can't draw the objects in the right place and you certainly can't check for collisions.
You basically want to use the same rects that you use for drawing the objects.
Some code examples:
If your coordinates point to the middle of the stickman you would use something like the following:
if (CGRectIntersectsRect(CGRectMake(stickman.x-stickman.width/2,
stickman.y-stickman.height/2,
stickman.width,
stickman.height),
CGRectMake(spikes.x-spikes.width/2,
spikes.y-spikes.height/2,
spikes.width,
spikes.height))) {
// Do whatever it is you need to do. For instance:
[self showEndScreen];
}
If your coordinates point to the top left corner of your stickman you would use:
if (CGRectIntersectsRect(CGRectMake(stickman.x,
stickman.y,
stickman.width,
stickman.height),
CGRectMake(spikes.x,
spikes.y,
spikes.width,
spikes.height))) {
// Do whatever it is you need to do. For instance:
[self showEndScreen];
}
If I might give you a suggestion, I would suggest storing the coordinates and sizes in a CGRect, so that you don't have to create a new CGRect every time you're checking for collision.