The iOS and OS X NSNumberFormatterStyle enum gained 4 new values with the new iOS 9 and OS X 10.11 SDK! They sound cool and useful, but Apple's documentation and even Google had nothing to say about them!
What do these new values do when passed to a formula, and how are they different than the old values?
In iOS 9.0 or OS X 10.11 〉Frameworks 〉Foundation 〉NSNumberFormatter.h lines 46-57:
typedef NS_ENUM(NSUInteger, NSNumberFormatterStyle) {
NSNumberFormatterNoStyle = kCFNumberFormatterNoStyle,
NSNumberFormatterDecimalStyle = kCFNumberFormatterDecimalStyle,
NSNumberFormatterCurrencyStyle = kCFNumberFormatterCurrencyStyle,
NSNumberFormatterPercentStyle = kCFNumberFormatterPercentStyle,
NSNumberFormatterScientificStyle = kCFNumberFormatterScientificStyle,
NSNumberFormatterSpellOutStyle = kCFNumberFormatterSpellOutStyle,
NSNumberFormatterOrdinalStyle NS_ENUM_AVAILABLE(10_11, 9_0) = kCFNumberFormatterOrdinalStyle,
NSNumberFormatterCurrencyISOCodeStyle NS_ENUM_AVAILABLE(10_11, 9_0) = kCFNumberFormatterCurrencyISOCodeStyle,
NSNumberFormatterCurrencyPluralStyle NS_ENUM_AVAILABLE(10_11, 9_0) = kCFNumberFormatterCurrencyPluralStyle,
NSNumberFormatterCurrencyAccountingStyle NS_ENUM_AVAILABLE(10_11, 9_0) = kCFNumberFormatterCurrencyAccountingStyle,
};
Take a look at this year's Session 227 - What's New in Internationalization (video; text)
In the video it is explained at 18:34 - here is a screenshot of this particular slide:
In addition to the existing NSNumberFormatterStyles Apple introduced four new styles in iOS 9 and OS X 10.11.
In addition to the already existing 'currency style, we now have 'currency ISO code style, as well 'currency plural style' and 'currency accounting style.' Interestingly here for 'currency accounting style, if you pass it a negative number, it presents it surrounded by parentheses.
This is common in accounting circles.
To see what these currency styles look like, take a look ate the picture above.
The ordinal style can be used for ordered lists.
1st Foo
2nd Bar
...
42nd Foo Bar
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.
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).
I have set font traits (bold, light) for several of my labels in an OSX app and now I get these warnings:
.../MainMenu.xib:9:
Xcode.IDEInterfaceBuilder.Cocoa.NSObject.BroadSystemFontWeights
without any explanation. Often the meant label isn't even selected when I click on the warnings. Can someone shed a light on what those warnings mean and how to get rid of them?
This is a warning shown starting from Xcode 7 when UI elements like a label or table view column header use a font style or variation that is not available on older OSes (and of course your project is still targeting them).
In my project a table view column header was using the system font with the "medium" font style variation instead of regular, in a project targeting OS X 10.9+.
The weird thing is I had to restart Xcode as Interface Builder refused to change the style of the control. Possibly a small glitch of this early 7.0.1 Xcode version.
Current answer almost gets it, but problem is not with font styles being unavailable in older targets, it's with Xcode not handling them properly, see full blog post for details.
If you want to keep your styles, 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
}
}
}
If you don't really care about the styles, use regular weight font for all text, it should solve the problem, see my earlier answer for available options.
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.
My app is a logbook for pilots and I'd like to give the user the option of putting the app in the time zone of their choice. Airline pilots may fly across the world but have to reference their home base time zone when entering flight information. I want to offer a UI that allows them to select a time zone option such as "Local" (which is device local, depending on their location), "UTC", and then the hard one "custom".
I'm using MonoTouch.Dialog which allows you to wire up a collection but the problem is in iOS the list of time zones is rather long. I use the System.TimeZoneInfo namespace to retrieve the list of time zones just like in Windows. However, iOS uses a presentation such as "United States/New York, United States/XYZ, etc.". So to keep this list manageable I'm going to need to break this up by splitting on the / so I can first present a list of countries, the user will tap that and a secondary list will then present in a UITableView which is the regions such as "New York." I'll then capture the time zone and use the System.TimeZoneInfo methods to convert from UTC to the custom time zone.
My question is how, particularly in MonoTouch.Dialog, can I have a collection and then a sub-collection. i.e. a UITableView of Countries with a disclosure indicator that takes you to the regions for the country?
On this same note, has anyone else implemented a "time zone" selector/picker in iOS (Xcode or MonoTouch)?
Thank you for your ideas and help with this problem.
The following will get you the UI you are looking for:
var groups = from tz in TimeZoneInfo.GetSystemTimeZones ()
let name = tz.ToString ()
let idx = name.IndexOf ('/')
where idx != -1
let first = name.Substring (0, idx)
group tz by first into g
select new { Region = g.Key, Zones=g };
var root = new RootElement ("TimeZones"){
new Section ("Regions"){
from r in groups
select (Element) new RootElement (r.Region.ToString ()){
new Section () {
from z in r.Zones
select (Element) new StringElement (z.ToString ())
}
}
}
};
dvc = new DialogViewController (root);
It produces this UI:
(source: tirania.org)
And the nested elements look like this:
(source: tirania.org)
On this same note, has anyone else implemented a "time zone" selector/picker in iOS (Xcode or MonoTouch)?
I have not seen one doing exactly this. However this article shows you how to use UIPickerView to implement your own pickers (close to what you want). It should not be too hard to convert this into C#.
Once you have your own UITimeZonePicker then it should be easy to create a TimeZoneElement for MonoTouch.Dialog (mostly copy/pasting DateElement).