El Capitan introduced San Francisco system font, which has proportional digits by default.
This makes numbers in table columns look jagged and hard to compare:
I'd like to enable fixed-width numbers option for the font, but keep using the default system font and keep backwards compatibility with earlier versions of OS X.
In Interface Builder selecting font > Font Panel > Typography > Monospaced Numbers does not affect the font (XIB file remains unchanged).
What's the right way to set monospaced numbers in OS X table view columns? (I suspect IB is unusable for this, so a programmatic solution is OK too).
Just use +[NSFont monospacedDigitSystemFontOfSize:weight:] when it's available. It's new in 10.11, but still not in the NSFont docs. It's in the headers and was discussed in the WWDC 2015 videos. So, something like:
if ([NSFont respondsToSelector:#selector(monospacedDigitSystemFontOfSize:weight:)])
textField.font = [NSFont monospacedDigitSystemFontOfSize:textField.font.pointSize weight:NSFontWeightRegular];
Here's a Swift extension that gives you a monospaced digits font with high legibility.
extension NSFont {
var legibleNumbersVariant: NSFont {
let features = [
[NSFontFeatureTypeIdentifierKey: kNumberSpacingType,
NSFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector],
[NSFontFeatureTypeIdentifierKey: kStylisticAlternativesType,
NSFontFeatureSelectorIdentifierKey: kStylisticAltSixOnSelector]
]
let descriptor = fontDescriptor.addingAttributes([NSFontFeatureSettingsAttribute: features])
return NSFont(descriptor: descriptor, size: pointSize) ?? self
}
}
Treat the following as pseudo-code, quickly done, not throughly tested, etc.
Given an NSFont which represents a font which has monospaced numbers as a feature the following method will produce another NSFont with that feature selected:
- (NSFont *) newMonospaceNumbersFont:(NSFont *)font
{
CTFontDescriptorRef origDesc = CTFontCopyFontDescriptor((__bridge CTFontRef)font);
CTFontDescriptorRef monoDesc = CTFontDescriptorCreateCopyWithFeature(origDesc, (__bridge CFNumberRef)#(kNumberSpacingType), (__bridge CFNumberRef)#(kMonospacedNumbersSelector));
CFRelease(origDesc);
CTFontRef monoFont = CTFontCreateWithFontDescriptor(monoDesc, font.pointSize, NULL);
CFRelease(monoDesc);
return (__bridge_transfer NSFont *)monoFont;
}
You can use this, say, to take the current font of a UI element and convert it to one with monospace numbers.
HTH
Variant for Swift
Assuming res is the NSTextField with the number to display:
let origDesc = CTFontCopyFontDescriptor(res.font!)
let monoDesc = CTFontDescriptorCreateCopyWithFeature(origDesc, kNumberSpacingType, kMonospacedNumbersSelector)
let monoFont = CTFontCreateWithFontDescriptor(monoDesc, res.font!.pointSize, nil)
res.font = monoFont
In my experience, the "font panel" functionality isn't well defined and I usually just ignore it whenever I'm messing with a XIB or Storyboard.
What should work is to go back to that "Font" attribute in the Text Field Cell attributes inspector and then select "User Fixed Pitch" from the Font drop down menu (the choice should automatically default to size 11).
If you bump the font size up a point, it'll magically switch to Monaco (the default fixed width font).
Related
I have charts with 15-17 lines and the cursor modifier cuts off the view at 6 on phones. It looks great on tablets, but on phones, as said, only shows six. Is there a way to decrease the text size in the modifier to fit more lines?
As for Android I would suggest to take a look on Custom Cursors example and use it as a base. In this example CustomXySeriesTooltip inherits from TextView which is used to render tooltip's text. So you can set font size for it like on regular TextView ( in ctor or internalUpdate override ):
public CustomXySeriesTooltip(Context context, XySeriesInfo seriesInfo) {
super(context, seriesInfo);
this.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
}
And the code for Xamarin.Android should be similar to Java one.
As for iOS - you can use dataStyle property provided by SCICursorModifierStyle which allows to specify font size:
SCITextFormattingStyle * textFormatting = [SCITextFormattingStyle new];
textFormatting.fontSize = 16;
textFormatting.fontName = #"Helvetica";
cursor.style.dataStyle = textFormatting;
Or you can create custom modifier like in this example.
I recently updated XCode to 7.0 and I get this warning message:
Xcode.IDEInterfaceBuilder.Cocoa.NSObject.BroadSystemFontWeights
What does it mean and how do I get rid of it ?
I got the same error when I set the font weight to Semibold to a label with system font. This weight is available for the new system font (San Francisco) but not for the old Helvetica Neue, so I guess that that error means we won't get the right weight on older OS.
Changing the font to a weight available also for Helvetica Neue, Bold in my case, has fixed the error for me.
The problem is not with changing system font weight, the problem is with Xcode not handling this properly – contradicting statement, I know, see full blog post for details. There are three scenarios.
First – explicit typography is not important, regular weight is acceptable. Then stick with Marco's answer and use explicit regular weight.
Second – explicit typography is preferable, but can be compromised on older systems. This is the default behaviour right now, Xcode simply shows a warning and uses regular font on pre-10.11 targets. If you use adaptive layouts, everything should be fine. To get rid of the warning, you can simply set higher target in storyboard inspector:
Note, if your storyboard uses fallback features for earlier targets, they might become disabled, which will cause problems – I haven't come across any so far.
Third – explicit typography is a must. In this case you can use custom textfield with custom inspectable property. Open up identity inspector and set custom class to TextField, preferred font weight attribute will show up in attribute inspector, set the required value, build and enjoy the result.
import AppKit
#IBDesignable public class TextField: NSTextField
{
#IBInspectable public var preferredFontWeight: Int = 0
override public func awakeFromNib() {
if #available(OSX 10.11, *) {
return
}
guard
let weight: Int = self.preferredFontWeight where weight > 0,
let font: NSFont = self.font,
let name: String = font.familyName,
let manager: NSFontManager = NSFontManager.sharedFontManager() else {
return
}
// Full details here – https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSFontManager_Class/#//apple_ref/occ/instm/NSFontManager/convertWeight:ofFont:
//
// 1 – ultralight
// 2 – thin
// 3 – light, extralight
// 4 – book
// 5 – regular, display
// 6 – medium
// 7 – demi, demibold
// 8 – semi, semibold
// 9 – bold
// 10 – extra, extrabold
// 11 – heavy
// 12 – black
// 13 – ultrablack
// 14 – extrablack
if let font: NSFont = manager.fontWithFamily(name, traits: manager.traitsOfFont(font), weight: weight, size: font.pointSize) {
self.font = font
}
}
}
P.S. Bold weight works probably because it uses a slightly different logic – there's boldSystemFontOfSize(_:) that's available since OS X 10.0, unlike many other methods, which storyboard might rely upon.
How can I use different system fonts for the line //pointsLabel.font = FontHUD, no custom font but different fonts available in the system
//"points" label
var pointsLabel = UILabel(frame: CGRectMake(ScreenWidth-340, 30, 140, 70))
pointsLabel.backgroundColor = UIColor.clearColor()
//pointsLabel.font = FontHUD
pointsLabel.text = " Points:"
self.addSubview(pointsLabel)
You could use UIFont.preferredFontForTextStyle(style: String) and pass any of the following as the style:
UIFontTextStyleHeadline
UIFontTextStyleSubheadline
UIFontTextStyleBody
UIFontTextStyleFootnote
UIFontTextStyleCaption1
UIFontTextStyleCaption2
On a bit of a side note - an advantage of using preferredFontForTextStyle is that you can use it to make your app support Dynamic Type because the size of the font returned varies depending on the user's preferred text size (set in the Settings app under Display & Brightness -> Text Size). To fully support dynamic type you should listen for changes in the preferred font size using NSNotifcationCenter and observing UIContentSizeCategoryDidChangeNotification, then updating your labels/textviews appropriately.
I have a storyboard with labels. The label's font is set to System 25.
I wanted to make the font size dynamic, and I set it by code now.
I set breakpoints, so I know that "25" is actually chosen in my code, but the font size still is smaller than when I set it in the storyboard designer.
Does anybody perhaps spot where I might have gone wrong or any caveats that I might have missed?
//set label font size
CGFloat nFontSize;
if (bIsIPad)
{
nFontSize=25.0;
}
else if (bIsIPhone_3GS_4_4s_Or_iPodTouch_3_4)
{
nFontSize=12.0;
}
else if (bIsIphone_5_Or_IPodTouch_5)
{
nFontSize=25.0;
}
UIFont *nFont = [UIFont fontWithName:#"System" size:nFontSize];
captionLabel0.font = nFont;
captionLabel1.font = nFont;
It seems that "fontWithName:#"System"" is not the same as "[UIFont systemFontOfSize:nFontSize];"
The storyboard property page seems to reflect "systemFontOfSize" when it displays the font "System".
When I chose "systemFontOfSize", the results were the same as in the storyboard.
You need to connect your label to outlet (storyboard).
And after that, you set the font size for this label.
I'm trying to diagnose a problem in UKSyntaxColoredTextDocument 0.4 http://www.zathras.de/angelweb/blog-uksctd-oh-four.htm where text that actually lives in a different font than the one you have specified disappears as you type. (You can download and try out this cool utility to see this problem for yourself...)
Here's the background: This is some syntax coloring code that recolors as you type. It works great, but if you enter some characters that are not a part of the font set for that text view (e.g. Monaco, Helvetica) ... for instance, a symbol character or something in Japanese, which actually uses fonts like ZapfDingbatsITC or HiraKakuProN-W3 to display it, then those characters are not displayed as you type.
Let's say you have some text like this: fdsafd[☀]sfds‡[☀☀☀][日本語]...
If you paste that into the text field, and switch among syntax coloring from the popup, this invokes oldRecolorRange:, with this line:
[[textView textStorage] replaceCharactersInRange: range withAttributedString: vString];
Here, things behave as I would expect. The ASCII text, the symbols, and the Japanese text are all visible. The value of [textView textStorage] starts out, and ends up, something like this: (This is output of gdb; it's not showing the unicode characters, don't worry about that.)
df{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}?{
NSFont = "ZapfDingbatsITC 20.00 pt. P [] (0x001ae720) fobj=0x001bb370, spc=5.56";
}fdsafd[{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}?{
NSFont = "HiraKakuProN-W3 20.00 pt. P [] (0x001b59e0) fobj=0x001bb600, spc=6.66";
}]sfds[{
...
... even after setting the new value to be
dffdsafd[?]sfds[???][???] Nihddfdfffdfdd{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}
In other words, the "foreign" fonts needed to display this string are preserved automatically somehow, even though the fonts are not specified in the replacement string.
However, when you type in one character at a time, a different call of replaceCharactersInRange:withAttributedString: in the method recolorRange: results in an attributed string that is only in the base font -- no foreign-character fonts have been added for us, so the characters out of the range of the main font are not visible at all!
dffdsafd[?]sfds[???][???] Nihddfdfffdfddx{
NSFont = "LucidaGrande 20.00 pt. P [] (0x001a3380) fobj=0x001a4970, spc=6.33";
}
Any idea why this method would be working one way in one circumstance and not in another? Is there some kind of switch that I can pass to give the NSTextStorage/NSAttributedString a hint that we want the text to display foreign characters?
Try [[textView textStorage] fixFontAttributeInRange:range]; after the [[textView textStorage] replaceCharactersInRange: range withAttributedString: vString] in recolorRange:
I think the problem is editing the text storage again in response to processEditing, which is already the tail end of an edit. -[NSTextStorage processEditing] uses fixFontAttributeInRange:, but since you're trying to edit again, something is going wrong and the fix behavior is being dropped.
When you do it for the whole document, there is a normal beginEditing/endEditing/processEditing sequence which causes fixFontAttributeInRange: to be called happily.