UILabel how to tighten letter spacing - ios

I would like to know how to programatically "Tighten Letter Spacing"?
This option is available for a UILabel made in a xib file, and is really handy sometimes.
I know this question has been asked before, but I don't see an answer that mentions this beeing available in the interface builder, so I was curious...

You are probably looking for this:
#property(nonatomic) BOOL adjustsLetterSpacingToFitWidth
Property of UILabel new in iOS6.

You might want to use UILabel property:
allowsDefaultTighteningForTruncation: Bool
and set it to true. (Default is false)
According to Apple Documentation:
When this property is set to true, the label tightens intercharacter spacing of its text before allowing any truncation to occur. The label determines the maximum amount of tightening automatically based on the font, current line width, line break mode, and other relevant information.
https://developer.apple.com/reference/uikit/uilabel/1620533-allowsdefaulttighteningfortrunca

adjustsLetterSpacingToFitWidth is deprecated as of iOS 7.
You'd now (as of iOS 8) probably want to do something like:
NSAttributedString *as =
[[NSAttributedString alloc] initWithString:#"Kerninating all the strings"
attributes:#{NSKernAttributeName : #(-2.0)}];
label.attributedText = as;

Related

UILabel wrong word wrap in iOS 11

I have problem with application using XIBs without autolayout. I don't know if this is important information.
I have UILabel with 2 lines using word wrap. In iOS 10 word wrap was working correctly, and first line contained one word + special character, for example ampersand. Example:
Then on iOS 11 word wrap is working somehow wrong and puts ampresand to the second line:
This is problematic as longer words, that normally fitted on second line now are not being shown correctly. Any idea what has changed? I know about safeArea but it doesn't look like reason. Any ideas how to move that ampersand to the top where is plenty of space for it?
Rest of the settings:
This is a change by Apple to prevent widowed lines. From a design perspective, it is preferred to avoid having a single word on a line of text. UILabel now breaks the line in a way that the second line of text always has at least 2 words on it.
See the answer below for an option to disable it.
Also here's a good article about "widowed" and "orphaned" text.
Since iOS 14 you can use lineBreakStrategy property of UILabel instance to control this behavior.
Available values are:
NSParagraphStyle.LineBreakStrategy() // none
NSParagraphStyle.LineBreakStrategy.pushOut
NSParagraphStyle.LineBreakStrategy.hangulWordPriority
NSParagraphStyle.LineBreakStrategy.standard
To disable this behavior using Swift:
if #available(iOS 14.0, *) {
label.lineBreakStrategy = []
}
// Alternatives
// label.lineBreakStrategy = NSParagraphStyle.LineBreakStrategy()
// label.lineBreakStrategy = .init(rawValue: 0)
// label.lineBreakStrategy = .init()
To make it work on lower iOS versions, you can use NSAttributedString:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakStrategy = []
let attributedString = NSAttributedString(string: "Your text here", attributes: [
.paragraphStyle: paragraphStyle
])
let label = UILabel()
label.attributedText = attributedString
Objective-C:
if (#available(iOS 14.0, *)) {
label.lineBreakStrategy = NSLineBreakStrategyNone;
}
Launching the app with the arguments -NSAllowsDefaultLineBreakStrategy NO (an undocumented defaults setting) seems to force back to the old behavior. Alternatively, you can set NSAllowsDefaultLineBreakStrategy to NO in NSUserDefaults at startup (Apple registers a default of YES for that value when UILabel or the string drawing code is initialized, it appears, so you would need to register an overriding value after that, or insert it into the NSArgumentDomain, or just set the default persistently).
Apple may consider that private API and reject apps that use it; I'm not sure. I have not tried this in a shipping app. However, it does work in quick testing -- saw the setting in NSUserDefaults and found changing it altered the behavior.
This is not really an answer, but I want to add an illustration of how it is a general problem, not at all related to ampersands.
Both of these UILabels have identical width constraints, and the text is almost identical. But the second has the word wrap I would expect. The first is incorrect, the "about" can clearly stay on the first line.
A bit of a hack but you can add some zero width spaces to the end of the string to restore the old behaviour, without affecting the layout of the string otherwise that you'd get from normal spaces:
let zeroWidthSpace: Character = "\u{200B}"
let spacingForWordWrapping = String(repeating: zeroWidthSpace, count: 6)
label.text = "oneText & two" + spacingForWordWrapping
It seems that replacing the space before the ampersand with a non-breaking space (U+00A0) keeps the ampersand on the same line. Depending on how you are generating the text for the label, this might not be easy to automate (maybe you really do need the ampersand to be on the second line in some cases).
An option may be to use a UITextView instead -- that does not seem to have this behavior. If you set the NSTextContainer.lineFragmentPadding to 0, the textContainerInset to UIEdgeInsetsZero, and turn off all scrolling (scrollEnabled, bounces, scroll indicators, etc.) it will display similarly to a UILabel, though not with as much constraint flexibility. It's not a drop-in replacement, but in some situations it's acceptable.
As a simple (hacky) workaround, you can often get the correct behaviour with a UILabel by adding spaces at the end of your text. Using your example:
Wraps the new (undesired) way:
"oneText & two."
Wraps the old way:
"oneText & two. " (note the 2 extra spaces at the end of the string)
The obvious downside is if those extra spaces get forced to a new line by themselves, but for something simple like a title it's often enough.

iOS SDK: Difference between UIButton setTitleForState and UIButton titleLabel.text

I have this issue with a custom UIView where I have a UIButton subview, I want to set the button's text on initialization based on some condition like this:
- (void)awakeFromNib {
[super awakeFromNib];
//check for some conditions
self.testButton.titleLabel.text=#"Some Title";
}
Nothing happens and the button's text is the same as defined in the nib file, however if I change the implementation to:
- (void)awakeFromNib {
[super awakeFromNib];
//check for some conditions
[self.testButton setTitle:#"Some Title" forState:UIControlStateNormal];
}
It works as expected.
Can somebody please explain to me the difference between the two approaches? and when to use each?
EDIT:
the suggested answer doesn't explain my situation, I tested changing the button's text from another button's action like this:
- (IBAction)otherButtonClicked:(id)sender {
self.testButton.titleLabel.text=#"Some Title";
}
and the button's text changed. I just want to understand that behaviour.
Exact answer is
titleLabel
Do not use the label object to set the text color or the shadow color. Instead, use the setTitleColor:forState: and setTitleShadowColor:forState: methods of this class to make those changes.
The titleLabel property returns a value even if the button has not
been displayed yet. The value of the property is nil for system
buttons.
setTitle
Use this method to set the title for the button. The title you specify
derives its formatting from the button’s associated label object. If
you set both a title and an attributed title for the button, the
button prefers the use of the attributed title over this one.
At a minimum, you should set the value for the normal state. If a
title is not specified for a state, the default behavior is to use the
title associated with the UIControlStateNormal state. If the value for
UIControlStateNormal is not set, then the property defaults to a
system value.
Title label access is given to adjust other properties of the label such as font but setting titleLabel text does not work.
It is because UIButton class has inner implementation to set the text based on different states of the button like selected/highlighted etc which overrides label text.
The accepted answer is correct, I just add this here to elaborate a bit (comments are too short)
There's not much to explain here. The title is simply not meant to set the text at all. My guess is that the internal workings of UIButton make it save the text somewhere else as well (for different states). It uses a normal UILabel to eventually display that, because that's convenient and easy to understand. Setting the text of that does not change the button in all cases, which probably ultimately depends on the drawing cycle. I assume when it's drawn, laid out, or the like it "replaces" the label's text with its other saved variant at some point.
Now you might wonder why Apple did then expose the UILabel and thus seemed to make the text editable then.
Legacy is probably one aspect of this decision (IIRC you could once set the button's title that way). Although old code doesn't result in the desired behavior, it at least didn't crash immediately. Also, a lot of code simply wants to get the text and expects a label, that works perfectly fine as ever.
Second, designing it totally different seems overkill. To avoid that, they would have to use a subclass of UILabel which prevents you from setting the text or something and use that. Or skip it (and thus legacy support) completely and only offer the setTitle:forState: method. That seems like a bit much for a simple text container like a Label.
Ultimately it's a design choice made by Apple. You can't set the title text directly and there's no case in which you should do it any way other than by using setTitle:forState:

Custom keyboard with native prediction in iOS 8

The goal: to create a custom keyboard for Russian lang with QuickType (Predictive) which should look like native (I can't post image because of small reputation but I guess it's clear to understand) with some changes: own algorithm to show words; user can chose from more than 3 options
I've found out that it can not be done by standart features (like "set some property like quickType to YES"), but may be exists some another way to do it? e.g. create custom view or smth like that, so the question is:
Can I do so by custom view (with height greater than "215 +/- px") or is there some other way? And will Apple take it then?
UPD It's important that custom looks exactly as native.
You can add your custom word completion view as a sub view of the keyboard (the same way you add the buttons for your keys). Of course you will need to increase the height of the keyboard in order to provide the additional height for your completion view.
Apple Documentation
You can adjust the height of your custom keyboard’s primary view using Auto Layout. By default, a custom keyboard is sized to match the system keyboard, according to screen size and device orientation. A custom keyboard’s width is always set by the system to equal the current screen width. To adjust a custom keyboard’s height, change its primary view's height constraint.
You can also find a code sample on that page. I see no reason Apple will reject based on what you're describing.
Changing the height is possible. Check out this question iOS 8 Custom Keyboard: Changing the Height
You can provide a custom view to show prediction. 'Touchpal' in the App Store may be helpful for you. The 'Touchpal' English keyboard has some QuickType features just like system keyboard.
Your custom keyboard look and feel and your predictive mechanics (QuickType like) are all your responsibilities. There is no way to just copy or enable something. You should just program another absolutely the same keyboard from scratch and another QuickType-like algorithm. iOS8 just provides you with empty view that you can change height for.
Take a look at the UILexicon object and especially at the UITextChecker:
UITextChecker *checker = [[UITextChecker alloc] init];
NSRange checkRange = NSMakeRange(0, text.length);
NSRange misspelledRange = [checker rangeOfMisspelledWordInString:text
range:checkRange
startingAt:checkRange.location
wrap:NO
language:#"en_US"];
NSArray *arrayCorrected = [checker guessesForWordRange:misspelledRange
inString:text
language:#"en_US"];
return [arrayCorrected objectAtIndex:0];
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextChecker_Class/index.html

UITextView font is nil

I created a UITextView with a font size of 14 in a storyboard and hooked it up to the detailDescriptionLabel property of my ViewController. This code is in viewDidLoad:
self.detailDescriptionLabel.font=[UIFont systemFontOfSize:10];
NSLog(#"text is %#; font is %#", self.detailDescriptionLabel.text, self.detailDescriptionLabel.font);
The console output follows:
text is Lorem Ipsum; font is (null)
Why is the font set to nil? The setFont: is working; the font does shrink. I want to get the font so after a gesture I can call lineHeight on the font. This way, I can find out which line has been tapped with the following code:
int line = [tap locationInView:tap.view].y / self.detailDescriptionLabel.font.lineHeight;
Here, too, the font is nil. line is set to -2147483648, which is obviously not what I want.
Try checking the "selectable" checkbox for this UITextView in Interface Builder. It's in the Attributes Inspector. Per #VahramDodoryan's comment below, you can then set selectable to false if you don't want to support selection.
I can't explain why this works, but it's probably a UIKit bug. I had an IBOutlet to a UITextView whose font property was nil, and it would not respond to any font or text-color changes in code until after its text property had been set. I arrived at this solution through trial-and-error.
If you're still encountering this issue on recent releases of iOS, consider opening a radar:
https://openradar.appspot.com/15854592
https://openradar.appspot.com/15196932
I tried changing every property and constraint , I had on my text view.
Including selectable as suggested above
In frustration in the end I deleted and re-added it and that was the unsatisfying fix.
You should try logging self.detailDescriptionLabel. The value might be null.

Different Text font at each line of UIlabel

Is there any way to give different font size to each line of a label with "n" no of lines.
I dont want to take multiple labels for this purpose.
plz help!!!
Starting with iOS 6, you can use NSAttributedString in UILabel.
An NSAttributedString object manages character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string.
NSMutableAttributedString *attrStr = ...
myLabel.attributedText = attrStr;
Yes, but You have to use UIWebView, pass your text in html format.
UILabel with NSAttributedString(iOS 6 and later).
Or UIWebView with html-strings, but my favorit is a UITextView with html-strings. You can use it like this:
UITextView *tView=[UITextView new];
[tView setValue:#"<b>foo</b>bar" forKey:#"contentToHTMLString"];
UITextViews are easier to handle then UIWebView, especially if you don't need all the functionality of the WebView.
If you are targeting iOS < 6.0 then by using UILabel its not at all possible. Else you can refer dasblinkenlight answer (for iOS > 6)
There are couple of methods by which you can implement same :
Use UIWebView
Create UILabel for different fonts you want and set their frame as you want to display.

Resources