I'm currently working on an app that uses the "ChalkboardSE-Regular" font and my deployment target is 4.0+. This font was not available in 4.1 but it is supported in 4.3. What would be the best way to go about checking if the font exists and if it does not, use another supported font on the <4.1 versions of iOS. [UIFont familyName] returns a list of these fonts "Chalkboard SE"
Thanks in advance!
T
[UIFont familyName] is supported back to iPhone OS 2.0 (before 2.0, third-party apps were not allowed on iPhone or iPod touch) , so I would use that to check to see if a font family exists on the current device, and if it doesn't exist, use a suitable fall-back font for that version of iOS. Here's John Gruber's list of iPhone fonts from the original iPhone in 2007 (contrasted with the fonts in Mac OS X of the day). I haven't checked them all, but the iOS fonts I did check are still in iOS 5:
http://daringfireball.net/misc/2007/07/iphone-osx-fonts
Here's an example of using [UIFont familyName]:
NSLog (#"Font families: %#", [UIFont familyNames]);
This will produce a list like this:
Font families: (
Thonburi,
"Snell Roundhand",
"Academy Engraved LET", ... et cetera.
Once you know the family name, you can use the UIFont class method fontNamesForFamilyName to get an NSArray of the names of all the fonts in the family. For example:
NSLog (#"Courier New family fonts: %#", [UIFont fontNamesForFamilyName:#"Courier New"]);
That will produce a list like this:
Courier New family fonts: (
CourierNewPSMT,
"CourierNewPS-BoldMT",
"CourierNewPS-BoldItalicMT",
"CourierNewPS-ItalicMT"
)
The following example code prints a list of each font in every family on the current device:
NSArray *fontFamilies = [UIFont familyNames];
for (int i = 0; i < [fontFamilies count]; i++)
{
NSString *fontFamily = [fontFamilies objectAtIndex:i];
NSArray *fontNames = [UIFont fontNamesForFamilyName:[fontFamilies objectAtIndex:i]];
NSLog (#"%#: %#", fontFamily, fontNames);
}
For more information, check out the iOS Developer Reference document for the UIFont class methods familyNames and fontNamesForFamilyName:.
If you use Swift you can print all fonts (see below). You can also check if the font exists.
for family in UIFont.familyNames {
print("\(family)")
for name in UIFont.fontNames(forFamilyName: family) {
print(" \(name)")
}
}
Swift 5.x
Forget those for-loops, this is the easiest way to see fonts supported by iOS.
Just run any of the following in a playground.
Family Names Only
Input
dump(UIFont.familyNames)
Output
▿ 75 elements
- "Copperplate"
- "Heiti SC"
- "Kohinoor Telugu"
...
Font Names Only
Input
dump(UIFont.familyNames.compactMap { UIFont.fontNames(forFamilyName: $0) })
Output
▿ 248 elements
- "Copperplate-Light"
- "Copperplate"
- "Copperplate-Bold"
...
Font Names for Specified Family Name
Input
dump(UIFont.fontNames(forFamilyName: "Helvetica Neue"))
Output
▿ 14 elements
- "HelveticaNeue-Italic"
- "HelveticaNeue-Bold"
- "HelveticaNeue-UltraLight"
- "HelveticaNeue-CondensedBlack"
...
This font was not available in 4.1 but it is supported in 4.3. What would be the best way to go about checking if the font exists
Simply ask for the font in the usual way using UIFont* f = [UIFont fontWithName:... size:...];. If the font isn't available, the result (f) will be nil.
(One way to guarantee the availability of a font is to include it in the app bundle...)
For iOS9 / Swift 2.0, none of above won't work as the syntax changed a little. I also personally prefer to use extension (I choose to create one for UIFont, as it fits the best and modified #API answer as this was the best one):
extension UIFont {
static func availableFonts() {
// Get all fonts families
for family in UIFont.familyNames() {
NSLog("\(family)")
// Show all fonts for any given family
for name in UIFont.fontNamesForFamilyName(family) {
NSLog(" \(name)")
}
}
}
}
Now you can just call:
UIFont.availableFonts()
And it will tell you all the fonts in the form of
: Bangla Sangam MN
: BanglaSangamMN-Bold
: BanglaSangamMN
: Zapfino
: Zapfino
Hope it helps!
This is what i did on objective c to find out if font is available or not
NSFont *font = [NSFont fontWithName:#"thefont" size:25.0];
if (font==nil) {
// thefont is available
} else {
// thefont is not available
}
Swift version:
UIFont.familyNames().sort( { $0 < $1 } ).forEach({ print("\($0)"); UIFont.fontNamesForFamilyName("\($0)").sort( { $0 < $1 } ).forEach({ print(" \($0)") }) })
Well, rather than writing a single line of code, you can just open http://iosfonts.com and check availability based on your iOS version support. You can also know how would it look like.
Here is a conversion of Steves answer to Swift code (for quick copy and paste purpose):
var fontFamilies = UIFont.familyNames()
for (var i:Int = 0; i < fontFamilies.count; i++) {
var fontFamily: NSString = fontFamilies[i] as NSString
var fontNames: NSArray = UIFont.fontNamesForFamilyName(fontFamilies[i] as String) as NSArray
NSLog ("%#: %#", fontFamily, fontNames)
}
Try to init with that font name, and if it's nil do something else. Swift code:
if let font = UIFont(name: name, size: size) { // ok } else { // not ok }
I figured that using swiftui preview, you can make a app that shows what each font looks like using the preview simulator.
struct TitleViewModifier_Previews:
PreviewProvider {
static var previews: some View {
List{
ForEach(UIFont.familyNames.sorted(),id: \.self){ family in
ForEach(UIFont.fontNames(forFamilyName: family), id: \.self){ eachFont in
Text(eachFont)
.font(.custom(eachFont, size: 22))
}
}
}
}
}
Here is what my preview looks like
Press the play button to make the list interactive and scrollable
For objective-c
for (NSString *family in UIFont.familyNames) {
NSLog(#"family %#",family);
for (NSString *name in [UIFont fontNamesForFamilyName:family]) {
NSLog(#" name = %#",name);
}
}
print("Font families: %#", UIFont.familyNames)
Swift 4.x
UIFont.familyNames().sort( { $0 < $1 } ).forEach({ print("\($0)"); UIFont.fontNamesForFamilyName("\($0)").sort( { $0 < $1 } ).forEach({ print(" \($0)") }) })
Swift 5.x
UIFont.familyNames.sorted( by: { $0 < $1 } ).forEach({ print("\($0)"); UIFont.fontNames(forFamilyName: "\($0)").sorted(by: { $0 < $1 } ).forEach({ print(" \($0)") }) })
To check if UIFont is registered:
let fontName = "Helvetica"
UIFont.familyNames.flatMap(UIFont.fontNames).contains(fontName)
Related
I am using this method to cross out a string
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
yourLabel.attributedText = attributeString
now, I am creating a UI test to test a label. I want to check if the label is crossed out (Strikethrough) or not.
How can I do that?
This is the UI test code
let mastertableviewTable = app.tables["masterTableview"]
let staticText = mastertableviewTable.staticTexts["task two"]
The only answer to this, is I shouldn't UI test how content looks like, but I should test if the specific content is available of not.
as there is no way in UI testing we can get objects attributes, like color, font size ...
You shall probably use screen snapshot comparison tool like
https://github.com/uber/ios-snapshot-test-case
It is pretty simple to install. Though tool I mentioned is designed to be used in unit testing it also runs perfectly in UI tests targets.
You can use attribute(attrName:location:range:).
var range: NSRange
var attributedText: NSAttributedString
...
if attributedText.attribute(NSStrikethroughStyleAttributeName, at: attributedText.length - 1, effectiveRange: &range) != nil {
// OK!
} else {
// Not OK!
}
I have a strange problem with iOS 13 system font. I am trying to load iOS default font San Francisco using the font name. But due to some iOS bug it's loading some other font like Times New Roman. I saw few problems like this here and here. But in my case I have to load the font with name because I am using a Utility class to globally set font name in app delegate. Is there any way to load the system font using font name in iOS 13?
// Set font here
MUIConstats.shared.defaultFontRegularName = UIFont.systemFont(ofSize: 17).fontName
// Get font from here
class func appFontRegularOf(size: CGFloat)-> UIFont{
if let fontName = MUIConstats.shared.defaultFontRegularName {
return UIFont(name:fontName, size: size) ?? UIFont.systemFont(ofSize:size)
}else{
return UIFont.systemFont(ofSize:size)
}
}
You can store the name of a nonsystem font, but if it's the system font the only thing you're allowed to store is the fact that it's the system font. This is a perfect opportunity for a union:
enum WhatFont {
case system
case name(String)
func fontOfSize(_ sz:CGFloat) -> UIFont? {
switch self {
case .system: return UIFont.systemFont(ofSize: sz)
case .name(let name): return UIFont(name: name, size: sz)
}
}
}
Test it:
let f1 = WhatFont.system
print(f1.fontOfSize(17))
let f2 = WhatFont.name("Georgia")
print(f2.fontOfSize(17))
I want to detect when a user changes the SIM card.
I tried using subscriberCellularProviderDidUpdate but after removing and reinserting the SIM card the closure/block never gets called. Also the instance property is deprecated. Is there a replacement?
subscriberCellularProviderDidUpdateNotifier appears to have been replaced with serviceSubscriberCellularProvidersDidUpdateNotifier as of iOS 12.
If you need to support iOS 11 or earlier in addition to iOS 12 you can something like:
let ct = CTTelephonyNetworkInfo()
if #available(iOS 12.0, *) {
ct.serviceSubscriberCellularProvidersDidUpdateNotifier = { (carrier) in
// carrier is a String
}
} else {
ct.subscriberCellularProviderDidUpdateNotifier = { (carrier) in
// carrier is a CTCarrier
}
}
I am developing an iOS app in Swift 3.
In this app I am listing all available fonts (system provided) but I would like to list all available characters for them too.
For example I am using Font Awesome to and I want the user to be able to select any of the characters/symbols from a list. How can I do this?
This is how I get an array of the fonts. How can I get an array of all characters for a selected font?
UIFont.familyNames.map({ UIFont.fontNames(forFamilyName: $0)}).reduce([]) { $0 + $1 }
For each UIFont, you have to get characterSet of that font. For example, I take first UIFont.
let firsttFont = UIFont.familyNames.first
let first = UIFont(name: firsttFont!, size: 14)
let fontDescriptor = first!.fontDescriptor
let characterSet : NSCharacterSet = fontDescriptor.object(forKey: UIFontDescriptorCharacterSetAttribute) as! NSCharacterSet
Then, use this extension to get all characters of that NSCharacterSet:
extension NSCharacterSet {
var characters:[String] {
var chars = [String]()
for plane:UInt8 in 0...16 {
if self.hasMemberInPlane(plane) {
let p0 = UInt32(plane) << 16
let p1 = (UInt32(plane) + 1) << 16
for c:UTF32Char in p0..<p1 {
if self.longCharacterIsMember(c) {
var c1 = c.littleEndian
let s = NSString(bytes: &c1, length: 4, encoding: String.Encoding.utf32LittleEndian.rawValue)!
chars.append(String(s))
}
}
}
}
return chars
}
}
(Ref: NSArray from NSCharacterset)
So, at last, just call characterSet.characters to get all characters (in String)
I don't think you'll be able to without a lot of coding. Here's a few links to Apple documentation:
In their main font page you'll have to scroll down a bit to get to a list of documentation, but in that list is their TrueType reference manual. The characters are stored as glyphs, meaning they are vector-based to allow for clean font sizes. (I believe the simple drop-down of font sizes in IB are merely "suggestions", and you can type in any size you care to.)
In that second link, scroll down to the lengthy list of font tables. One looks promising - the cmap table. But reading through this, it's possible to (a) have foreign characters like "umlaut A" or Chinese and (b) omit characters in each font. Also, this is just a lookup table - you'll then maybe need to use the mapping table to get the location of the glyph.
If you are targeting English only, you might be better off finding a way to check if the letters "Aa" exist for the font and display them.
Is there a way, using IOKit or something similar that does not involve downloading additional packages from the internet, that I can use to read a USB device's product name?
This is my current code...
func printSerialPaths(portIterator: io_iterator_t) {
var serialService: io_object_t
repeat {
serialService = IOIteratorNext(portIterator)
if (serialService != 0) {
var key: CFString! = "IOCalloutDevice"
var bsdPathAsCFtring: AnyObject? = IORegistryEntryCreateCFProperty(serialService, key, kCFAllocatorDefault, 0).takeUnretainedValue()
var bsdPath = bsdPathAsCFtring as! String?
if let path = bsdPath {
print(path)
}
var deviceNameCString: [CChar] = [CChar](count: 128, repeatedValue: 0)
let deviceNameResult = IORegistryEntryGetName(serialService, &deviceNameCString)
let deviceName = String.fromCString(&deviceNameCString)!
print("usb Device Name: \(deviceName)")
}
} while serialService != 0;
}
I have also tried using other CFStrings, such as "Product Name" in the IORegistryEntryCreateCFProperty() command as I've seen suggested elsewhere with no luck. If replacing that is all I need, where can I find the documentation for the rest of these strings?
The product name that I'm talking about is highlighted below. I'm not sure what its technical name would be.
If the io_service_t handle is to an IOUSBDevice/IOUSBHostDevice, it should have a property named "USB Product Name" (symbolic constant kUSBProductString, at least in C) - I believe that's what you're after. You can query it with IORegistryEntryCreateCFProperty() as you're already doing for the "IOCalloutDevice" property, which by the way is defined as the symbolic constant kIOCalloutDeviceKey.
If those constants do not exist in Swift when importing the IOKit module, just define your own constants and file a bug (Radar) with Apple about the omission.