UIFont.monospacedDigitSystemFontOfSize() not really monospaced? - ios

I wanted to use SF's monospaced digits font to display an integer number in a text field by changing its font as follows:
textField.font = UIFont.monospacedDigitSystemFont(textField.font!.pointSize, weight: UIFont.Weight.semibold)
But if I set the text of the text field in a 60Hz frequency, this is the result:
The width of the text is clearly not constant for a same amount of digits so it is moving all jittery because the text field is constrained to "leading" and "trailing" of the image underneath.
Why is this the case and how to fix it?
Another truly monospaced font like "Menlo" is behaving correctly:

So it seems like setting the "adjust to fit" option of the text field is overwriting the monospaced property of the font (even if the view is big enough to contain the text!)
My temporary solution at this point is to
Set textField.adjustsFontSizeToFitWidth to false
Set the monospaced font again (as it was somehow overwritten by adjustsFontSizeToFitWidth's setter)
Begin to change the text
When finished set textField.adjustsFontSizeToFitWidth to true again in order to correctly behave on user input
This is not what I originally wanted but it works as a workaround

I have a project that uses the "adjust to fit" option and if I set the monospaced property using didSet for the label outlet, it seems to work for me in Xcode 8 Beta 3.
#IBOutlet weak var textLabel: UILabel! {
didSet {
textLabel = UIFont.monospacedDigitSystemFont(ofSize: textLabel!.pointSize, weight: UIFontWeightRegular)
}
}

In my case, I was setting the font property of a UILabel to a monospaced digit font and using attributedText to set the text. This worked in iOS 9 but broke in iOS 10. The workaround is to explicitly set the font attribute in the attributed string.

I was having the same problem and did set code worked. Updated for Swift 4:
#IBOutlet weak var textLabel: UILabel! {
didSet {
label.font = UIFont.monospacedDigitSystemFont(ofSize: textLabel!.font!.pointSize, weight: UIFont.Weight.regular)
}
}

Related

System font renders as Times New Roman on iOS 13

I have some UILabel with the default system font. But when I install my app on iPad or iPhone with iOS 13.1 the fonts change to something like Times New Roman! Why does this happen? I am sure the label's text is Plain and the font is System. How can I fix this issue?
PS: I have downloaded all SF fonts from Apple web site, and still no luck!
I found the solution, the problem comes with detecting the current label's font. I changed:
descriptions.font = UIFont(name: (descriptions.font?.fontName)!, size: 22)
to
descriptions.font = UIFont.systemFont(ofSize: 22)
and problem solved.
Use UIFontDescriptor
I was having the same issue on iOS 13. Fixed it by using fontDescriptor instead of fontName. I have UILabel in my storyboard connected to its view controller via IBOutlet with font as Text Styles - Callout.
#IBOutlet weak var lblText: UILabel!
Below one didn't worked as expected and showing Times New Roman font:
let font = UIFont.init(name: lblText.font.fontName, size: 50.0)!
lblText.font = font
lblText.text = "Times Coding :)"
Solution using UIFontDescriptor:
let font = UIFont.init(descriptor: lblText.font.fontDescriptor, size: 50.0)
lblText.font = font
lblText.text = "Times Coding :)"
This way it will pick the font you set to a label in your storyboard, you don't need to hardcode the font name.
It seems like Apple is pushing to use the initializer with the weightage. Passing it with the name seems to break it ".SFUI-Regular".
The workaround for this is to use the function with weight like this : UIFont(systemFont:UIFont.systemFontSize, weight: .regular).

Proper Way to Mimick UITextField Placeholder Color

I have another object that I want to have the same color as the UITextField's default placeholder text color.
I know I can simply make a new UIColor with the same color, but this seems hacky and problematic if Apple changes the default UITextField color. I instead am looking for the proper way to access the UITextField color so that I can set another field to the same color?
Thanks.
From UITextField API in UIKit, the place holder color of UITextField is 70% of gray color and it is defined by the iOS SDK.
open var placeholder: String? // default is nil. string is drawn 70% gray
From Apple Doc.s
The placeholder string is drawn using a system-defined color.
Probably, we may not have an access to these system defined colors with any attributes given in iOS SDK.
Try this:-
#IBOutlet weak var textField: UITextField!
Now in viewDidLoad method:-
let placeHolederText = "PlaceHolder"
let attributedPlaceHolder = NSAttributedString(string: placeHolederText, attributes: [NSAttributedString.Key.foregroundColor : UIColor.red ,NSAttributedString.Key.font : UIFont.systemFont(ofSize: 12) ])
self.textField.attributedPlaceholder = attributedPlaceHolder
self.textField.borderStyle = .bezel
self.textField.tintColor = .gray
Result:-
I hope this will help you,
Thanks.

How to align Right-Justify UILabel?

Remark:
Implementing:
myLabel.textAlignment = .right
does not solves my problem, that is not what I am asking for.
What I am trying to achieve is to let the alignment for the label to be Right-Justify.
To make it more clear:
That's how left alignment looks:
And that's how justify alignment looks:
if you are not seeing any difference between the tow screenshots, you could recognize it by the right (trailing) constraint of the label, you will notice in the second screenshot the whole width of the label has been filled by the text.
As shown in the second screenshot, letting the label to be justified will make it Left-Justify by default, i.e the last line alignment is left.
How can I make let the label to be justified to the right? In other words, I want the text to be just like the 2nd screenshot except that I want the last short line to be shifted to the right.
If you wondering what is the purpose of doing such a thing, it would be appropriate for right to left languages.
Thanks to #user6788419 for mentioning the appropriate answer.
For achieving it, you should work with NSMutableParagraphStyle:
An object that enables changing the values of the subattributes in a
paragraph style attribute.
It gives you the ability to the alignment and baseWritingDirection simultaneously, which leads to the desired output:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var lblDescription: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let text: NSMutableAttributedString = NSMutableAttributedString(string: "In vertebrates, it is composed of blood cells suspended in blood plasma. Plasma, which constitutes 55% of blood fluid, is mostly water (92% by volume), and contains dissipated proteins...")
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .justified
paragraphStyle.baseWritingDirection = .rightToLeft
paragraphStyle.lineBreakMode = .byWordWrapping
text.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, text.length))
lblDescription.attributedText = text
}
}
The output would be:
There is not ENUM available for right justified!
You have to choose from NSTextAlignmentLeft,NSTextAlignmentRight,NSTextAlignmentCenter,NSTextAlignmentJustified,NSTextAlignmentNatural.
You have added screenshot of xcode's interface builder! once check it in simulator or device.
If you want space at left or right side in label with justified text then you can play with edge insets.
For example Left padding in label.

How to fit all numbers on my display label? - Basic Calculator

I'm a beginner in Swift and Xcode. As my very first project without tutorials I try to do basic Calculator app. My goal is to make it look like original calculator app on iOS 9. Everything works, but I don't know how to fit all numbers on the screen. In Apple app, if there are more numbers, they're getting smaller. How to do that?
For UITextField:
You have to set the adjustFontSizeToFitWidth property to yes and provide a suitable small value for the minimumFontSize.
Both together will cause the UITextField to reduce its font size to fit the string in its bounds.
let textfield = UITextField()
textfield.adjustsFontSizeToFitWidth = true
textfield.minimumFontSize = 5
// ... more
For UILabel:
You have to set the adjustsFontSizeToFitWidth property to yes and provide a suitable small value for the minimumScaleFactor.
Both together will cause the UILabel to reduce its font size to fit the string in its bounds.
let label = UILabel()
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.05
// ... more

UILabel Line Spacing

I am trying to set the line spacing in a UILabel as specified by Mike Slutsky here. It works correctly for the text I specify from the Storyboard. When I try to set the UILabel.text in code, it reverts back to the default line spacing. Can someone help me understand how to either:
Keep it from reverting to default, and use the settings I specified on the Storyboard or
Set the value in code.
I've seen a lot of examples around using NSAttribute and NSParagraph, but since it's now possible to set in the Storyboard, I would expect their may be a more straightforward answer. Many thanks for the help!
I set the "Height Multiple" as illustrated in the above link, and my only code is as follows:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
textView.text = "Some example text"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
If I remove the textView.text line, it displays correctly, otherwise it's set back to the default line spacing (or Height Multiple).
Here's what's going on. You set things up in the storyboard with custom line spacing. This means, even though you may not know it, that in the storyboard you have set the label's attributedText.
But if you then come along and set the label's text in code, as you are doing, you throw away the attributedText and therefore all the attributes that it had. That is why, as you rightly say, things revert to the default look of the label.
The solution is: instead of setting the label's text, set its attributedText. In particular, fetch the label's existing attributedText; assign it into an NSMutableAttributedString so you can change it; replace its string while keeping the attributes; and assign it back to the label's attributedText.
So for example (I have called my label lab - your textView is a bad choice, as a text view is whole different animal):
let text = self.lab.attributedText
let mas = NSMutableAttributedString(attributedString:text)
mas.replaceCharactersInRange(NSMakeRange(0, count(mas.string.utf16)),
withString: "Little poltergeists make up the principle form of material manifestation")
self.lab.attributedText = mas
UILabel has
#property(nonatomic, copy) NSAttributedString *attributedText
since iOS 6.0,
This property is nil by default. Assigning a new value to this property also replaces the value of the text property with the same string data, albeit without any formatting information. In addition, assigning a new a value updates the values in the font, textColor, and other style-related properties so that they reflect the style information starting at location 0 in the attributed string.
If you set textView.text = "Some example text" again, you will loose your attributes. You should only pick one of them and not switching between them if you are sure what you are doing
Here is #matt 's answer in Obj. C:
NSMutableAttributedString *mas = [self.lab.attributedText mutableCopy];
[mas replaceCharactersInRange:NSMakeRange(0, [mas.string length])
withString:#"Little poltergeists make up the principle form of material manifestation"];
self.lab.attributedText = mas;
Hope this helps someone!
Swift 3
Just copy & execute this code to see result
let label = UILabel()
let stringValue = "UILabel\nLine\nSpacing"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
label.attributedText = attrString

Resources