116 lines
4.7 KiB
Swift
116 lines
4.7 KiB
Swift
// Created by Keith Harrison https://useyourloaf.com
|
|
// Copyright (c) 2018 Keith Harrison. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the copyright holder nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
import UIKit
|
|
|
|
/// A utility type to help you use custom fonts with
|
|
/// dynamic type.
|
|
///
|
|
/// To use supply the name of a style dictionary
|
|
/// when creating the instance. The style
|
|
/// dictionary should be stored as a property
|
|
/// list file (by default in the main bundle).
|
|
///
|
|
/// If the plist file is invalid or missing the default
|
|
/// system font is used.
|
|
///
|
|
/// The style dictionary contains an entry for each text
|
|
/// style that uses the raw string value for each
|
|
/// `UIFontTextStyle` as the key.
|
|
///
|
|
/// The value of each entry is a dictionary with two keys:
|
|
///
|
|
/// + fontName: A String which is the font name.
|
|
/// + fontSize: A number which is the point size to use
|
|
/// at the `.large` content size.
|
|
///
|
|
/// For example to use a 17 pt Noteworthy-Bold font
|
|
/// for the `.headline` style at the `.large` content size:
|
|
///
|
|
/// <dict>
|
|
/// <key>UICTFontTextStyleHeadline</key>
|
|
/// <dict>
|
|
/// <key>fontName</key>
|
|
/// <string>Noteworthy-Bold</string>
|
|
/// <key>fontSize</key>
|
|
/// <integer>17</integer>
|
|
/// </dict>
|
|
/// </dict>
|
|
///
|
|
/// You do not need to include an entry for every text style
|
|
/// but if you try to use a text style that is not included
|
|
/// in the dictionary it will fallback to the system preferred
|
|
/// font.
|
|
public struct ScaledFont {
|
|
private struct FontDescription: Decodable {
|
|
let fontSize: CGFloat
|
|
let fontName: String
|
|
}
|
|
|
|
private typealias StyleDictionary = [UIFont.TextStyle.RawValue: FontDescription]
|
|
private var styleDictionary: StyleDictionary?
|
|
|
|
/// Create a `ScaledFont`
|
|
///
|
|
/// - Parameter fontName: Name of a plist file (without the extension)
|
|
/// that contains the style dictionary used to
|
|
/// scale fonts for each text style.
|
|
/// - Parameter bundle: Bundle containing the plist file.
|
|
/// Defaults to the main bundle.
|
|
|
|
public init(fontName: String, in bundle: Bundle = Bundle.main) {
|
|
if let url = bundle.url(forResource: fontName, withExtension: "plist"),
|
|
let data = try? Data(contentsOf: url) {
|
|
let decoder = PropertyListDecoder()
|
|
self.styleDictionary = try? decoder.decode(StyleDictionary.self, from: data)
|
|
}
|
|
}
|
|
|
|
/// Get the scaled font for the given text style using the
|
|
/// style dictionary supplied at initialization.
|
|
///
|
|
/// - Parameter textStyle: The `UIFontTextStyle` for the
|
|
/// font.
|
|
/// - Returns: A `UIFont` of the custom font that has been
|
|
/// scaled for the users currently selected preferred
|
|
/// text size.
|
|
///
|
|
/// - Note: If the style dictionary does not have
|
|
/// a font for this text style the default preferred
|
|
/// font is returned.
|
|
public func font(forTextStyle textStyle: UIFont.TextStyle) -> UIFont {
|
|
guard let fontDescription = styleDictionary?[textStyle.rawValue],
|
|
let font = UIFont(name: fontDescription.fontName, size: fontDescription.fontSize) else {
|
|
return UIFont.preferredFont(forTextStyle: textStyle)
|
|
}
|
|
|
|
let fontMetrics = UIFontMetrics(forTextStyle: textStyle)
|
|
return fontMetrics.scaledFont(for: font)
|
|
}
|
|
}
|