UILabel with no whitespace above or below text - objective-c

I have this UILabel in an app where the bottom of the text needs to (apppear to) rest on the edge of another uiview. The label also gets scaled by arbitrary amounts. The problem is that applying a scale to the label also scales the whitespace below the text in the label. So for instance scaling by 2.0f makes the whitespace twice as big, pushing the text farther away from the edge.
Is there a simple way of making a label perfectly fit the text's size so that the bottom pixel of the text is at the very bottom of the label view?

Let me present you, the most useful method for these situations:
[myString sizeWithFont: ....];
This method (and its multiple variations) return the size that a NSString instance will use, therefore, you can scale the UILabel to your needs. iOS lacks a "Vertical Alignment" option.
Here is a similar stackoverflow question, if you're still in doubt.

Related

NSTextField weird left margins

I've been looking for a solution for this one all day.
I have 4 NSTextFields (actually subclassed for a few custom operations), which all share the same X position.
The problem is, some have different styles (light, regular, bold) and might have different sizes.
What happens is that, even though the X origin is the same, the 1st letter always has a bit of (consistently different) left margins.
Please see pic: https://dl.dropbox.com/u/1977230/Screen%20Shot%202012-12-11%20at%2017.55.58.png
I want to make sure that all lines start exactly at the same point, say 100px from the left.
Any idea how to override that weird padding?
Cheers
The margin you're talking about I'm pretty sure is the lineFragmentPadding on the NSTextContainer that is used by the NSTextField.
See the NSTextContainer reference:
http://developer.apple.com/library/Mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSTextContainer_Class/Reference/Reference.html
And here's a page from the tutorial on Text Layout:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/TextLayout/Concepts/CalcTextLayout.html
It states in that article:
The typesetter makes one final adjustment when it actually fits text
into the rectangle. This adjustment is a small amount fixed by the
NSTextContainer object, called the line fragment padding, which
defines the portion on each end of the line fragment rectangle left
blank. Text is inset within the line fragment rectangle by this amount
(the rectangle itself is unaffected). Padding allows for small-scale
adjustment of the text container’s region at the edges and around any
holes and keeps text from directly abutting any other graphics
displayed near the region. You can change the padding from its default
value with the setLineFragmentPadding: method. Note that line fragment
padding isn’t a suitable means for expressing margins; you should set
the NSTextView object’s position and size for document margins or the
paragraph margin attributes for text margins.
Unfortunately, it looks like NSTextField's NSTextContainer and NSLayoutManager are private and inaccessible, but it appears they are accessible in an NSTextView:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSTextView_Class/Reference/Reference.html#//apple_ref/occ/cl/NSTextView
So that may be the class you need to subclass if you want to have minute control over this kind of functionality.
Have you looked into CoreText? I think it may provide the facilities to do what you're looking for. From the docs...
The Core Text layout engine is designed specifically to make simple text layout operations easy to do and to avoid side effects.
You are able to access "font metrics," which enable you to (from the docs)...
For every font, glyph designers provide a set of measurements, called metrics, which describe the spacing around each glyph in the font. The typesetter uses these metrics to determine glyph placement. Font metrics are parameters such as ascent, descent, leading, cap height, x-height, and so on.
EDIT:
It just may be that NSTextField was not designed for what you are trying to do. NSTextField does custom layout apart from a NSLayoutManager.
You may need to upgrade to a NSTextView, which always has a dedicated NSLayoutManager attached. Apple has some example projects you could search for using NSLayoutManager and NSTextView.
If you're using NSTextField to draw simple static text, take a look at AppKit additions to NSString. Use sizeWithAttributes: to get size of the "text" image. Then use the size to calculate rects for drawing. Finally use one of draw methods to actually draw text. Don't forget to "round" result of sizeWithAttributes! It's not pixel aligned.
But if you need to draw something more complex than simple label, use Core Text. You can find very good example of how to use it in twui source code.

How do I make a UITextView Wrap to accommodate text within it?

I have several UITextViews that contain numbers between one and three digits. I'd like these views to expand and shrink as the number becomes larger or smaller. At the moment the text is shrinking and the TextViews size remains the same.
I'd preferable like to do this using the xib file (I'm very surprised this isn't a meagre check box) but a coded answer would be great if this isn't possible.
I'd recommend using the contentSize property of the UITextView:
self.textView.frame = CGRectMake(self.textView.frame.origin.x, self.textView.frame.origin.y, self.textView.contentSize.width, self.textView.contentSize.height);

Draw bordered text efficiently in iOS

I have a view with custom drawRect method which has two text lines drawn in fixed width.
This view is being redrawn constantly at rate of about 16 timer per second with position of text and content of text changing all the time.
I also need my text to be drawn in such a way that it is clearly visible at any background, and for that purpose I do the following:
CGContextSetTextDrawingMode(ctx, kCGTextStroke); // Border mode
[string drawAtPoint:point withFont:font];
CGContextSetTextDrawingMode(ctx, kCGTextFill); // Text mode
[string drawAtPoint:point withFont:font];
This code draws the text in border mode with fixed line width, and then draws the text again at same position but in fill mode. In this way I get a blue text with white border around each letter.
The result is absolutely satisfactory for me except the performance.
Using Time Profiler I've noticed that about 70% of time spent for drawing the whole view is spent on execution of drawing the text in border (stroke) mode. But drawing in fill mode takes only 3% of the whole view drawing time. I think that this is not efficient considering the frequency of redrawing of the view.
So does anybody know how to draw the text with border around each letter in more efficient way?
Two options:
Use a shadow instead of drawing the outline: CGContextSetShadowWithColor
Cache the image of the string and it's outline using a CGLayer: CGLayerCreateWithContext
Explanation for 2:
Drawing text is highly optimized for the standard case where the letters are just filled with one color. Individual glyphs (letters) are not rendered from the outline each time. Instead the glyphs are drawn only once into buffered images which are cached and reused.
Since drawing outlines is seldom there's probably no caching of glyphs or other optimizations for this mode. So the idea is to do the caching yourself: Draw the whole string into one image, keep that image around and draw it instead of the text from within your drawRect: method.
There are several options how to do that:
Use a CGBitmapContext
Use UIGraphicsBeginImageContext
Use a CGLayer

NSString sizeWithAttributes: Inaccuracy

I want to know the width of an NSString displayed on the screen in pixels. So I can fit an NSTextField its bounds to be exactly the length of the string itself. So I used IB's "Label" NSTextField and for those who don't know what I mean, I got a label with title "Label", font "Lucida Grande 13px", not selectable, not editable, regular size, no background and according to IB its width is 38px wide.
If I want to get its width programatically I use
[#"Label" sizeWithAttributes: [NSDictionary dictionaryWithObject: [NSFont fontWithName: #"Lucida Grande" size: 13] forKey: NSFontAttributeName]].width
Which will give me 33.293457 . So that's about 5 px of the real width..
I believe what you are noticing is the difference between the frame of the control and it's layout frame. See Frame vs Layout Frame for a good explanation.
You are doing the right thing in computing the width. For a Label, there is no extra padding at the top or bottom of the control, which is why you saw no problems with the height of your control. However, on the left and right of the control, there are an additional three pixels. This can be verified by looking at the Frame and Layout of a Label control in IB.
So, the ~5 pixels you noticed is actually exactly 6. Once you take into account this padding, you should have no further trouble.
Unfortunately, there is no API to determine what the padding is for various controls (Push Buttons have an additional 6 pixels on each side). I would suggest filing a bug report at http://bugreport.apple.com - Apple does base what APIs they provide in part on the number of requests for them. While IB will tell you, you will need to code those values yourself. If they change in the next OS release, you will need to update your application.
That actually sounds reasonable. You are comparing two different widths; the width of a raw string vs. the width of a string contained in an NSTextField. The contained string likely has just a tad bit of padding on either end, among other minor differences.

Getting Justified Text in UITextField

How do I get justified text with UTTextField. It does have an textAlignment property. But the UITextAlignment constant only has left, right, and center justification.
What I am seeking is the Justified text common in word processing app with text flush with both left and right edges. This is a read only text field.
I have seen it in few iPhone apps. So it seems I am missing something.
It's a bit of an overkill maybe, but one way seems to be to use a WebView for it and style the text with CSS.
UILabel and UITextField do not support full-justified text. If you want it for a UITextField, you would have to create a subclass of UITextField and override drawTextInRect:, splitting the text into words and using sizeWithFont: to figure out how to space them along each line.
I cannot imagine what would be worth the trouble.