user1046037
user1046037

Reputation: 17725

System Font with custom size for text style

Aim:

I would like to know how to use a system font in my SwiftUI app with a custom size that supports dynamic size (that changes when the user changes the text size on the device, font size changes dynamically).

Problem:

I can use the standard .body, .title etc for system fonts, however I want to use a custom size which is slightly different however still want to make sure it works with dynamic types

My Failed Attempt:

//Font size doesn't change when the user changes his preferred text size on the device
Text("hello")
    .font(.system(size: 14, weight: .bold, design: .default))

Note:

I am targeting iOS 15, I am looking for something on the lines of the following for system font:

static func custom(_ name: String, size: CGFloat, relativeTo textStyle: Font.TextStyle) -> Font

Questions:

Upvotes: 1

Views: 793

Answers (2)

user1046037
user1046037

Reputation: 17725

Following Font function helps achieve custom font size relative to TextStyle:

static func custom(
    _ name: String,
    size: CGFloat,
    relativeTo textStyle: Font.TextStyle
) -> Font

Upvotes: 1

Pavel Alexeev
Pavel Alexeev

Reputation: 6081

I made it with somewhat hacky font size estimation based on current sizeCategory:


public enum AppTextStyle {
    case veryCustomTextStyle
    case anotherCustomTextStyle
}

struct ScaledFontModifier: ViewModifier {
    
    @Environment(\.sizeCategory) var sizeCategory
    var textStyle: AppTextStyle

    func body(content: Content) -> some View {
        content.font(font(for: textStyle))
    }
    
    private func font(for style: AppTextStyle) -> Font {
        switch style {
        case .veryCustomTextStyle:
            return .system(size: scaledValue(for: 42))
        case .anotherCustomTextStyle:
            return .system(size: scaledValue(for: 42), weight: .medium)
        }
    }

    private func scaledValue(for size: CGFloat) -> CGFloat {
        switch sizeCategory {
        case .extraSmall:
            return size - 3
        case .small:
            return size - 2
        case .medium:
            return size - 1
        case .large:
            return size
        case .extraLarge:
            return size + 2
        case .extraExtraLarge:
            return size + 4
        case .extraExtraExtraLarge:
            return size + 6
        case .accessibilityMedium:
            return size + 11
        case .accessibilityLarge:
            return size + 16
        case .accessibilityExtraLarge:
            return size + 23
        case .accessibilityExtraExtraLarge:
            return size + 30
        case .accessibilityExtraExtraExtraLarge:
            return size + 36
        @unknown default:
            return size
        }
    }
}

public extension View {
    func font(_ textStyle: AppTextStyle) -> some View {
        modifier(ScaledFontModifier(textStyle: textStyle))
    }
}

You can use it along the built-in fonts, or you can put all your app text styles in AppTextStyle enum:

Text("Hello")
    .font(.body)
Text("World")
    .font(.veryCustomTextStyle)

Upvotes: 0

Related Questions