忽略动态类型时修复 SwiftUI iOS 13+ 中自定义字体的大小

Fixing the size of a custom font in SwiftUI iOS 13+ when ignoring Dynamic Type

在我正在开发的应用程序中(iOS13 及更高版本的 SwiftUI),我导入了自定义字体,并使用以下方法加载字体":

func getDigitalXFontOfSize(size s : CGFloat) -> Font {
        return Font.custom("DigitalX", size: s);
}

我在视图中有一个文本对象,如下所示:

let font : Font = FontGetter.getDigitalXFontOfSize(20.0);

var body: some View {
        HStack {
            Text("some text").font(FontGetter)
        }
}

在 iOS 中,设置中有更改字体大小的选项,它指出:“支持动态类型的应用程序将调整为您在下面的首选阅读大小”。据我所知,SwiftUI 中的文本视图会根据动态类型值自动采用动态缩放字体。

现在我明白可访问性非常重要,如果用户想要更大的字体,他们应该能够得到一个等等。我的应用程序是网络游戏的附加组件,需要非常具体的布局'坚持非常大或非常小的文本(如 iOS 中可用的文本,例如 accessibilityExtraExtraExtraLarge

某些应用程序,例如 iOS 的 Reddit 应用程序,似乎完全忽略了在“设置”应用程序中设置的文本大小。

当您在“设置”应用中更改文本大小滑块时,我的应用中的文本大小也会发生变化,这是我不希望发生的。

我可以在我的应用程序中关闭动态类型支持并始终按照我指定的确切大小呈现字体吗?如果可以,怎么办?

我可以为我在应用程序中使用的特定文本视图禁用动态类型吗?

我花了很多时间在 SO 上搜索类似问题,但我似乎找不到 iOS 13 及更高版本或 SwiftUI 的解决方案。 iOS(或swift)的早期版本没有缩放以相同方式创建的自定义字体,但现在它们似乎可以。

编辑

在iOS14中,有一个创建固定字号的选项如下:

func getDigitalXFontOfSize(size s : CGFloat) -> Font {
        return Font.custom("DigitalX", fixedSize: s);
}

这似乎有效。但我也需要这样的东西 iOS 13 也。

一个小技巧

Apple 似乎没有给我们直接的方法来影响动态字体的最大大小。

为了避免非常小的字体大小,可以使用 minimumScaleFactor 修饰符,例如

.minimumScaleFactor(0.5)

要避免非常大的字体并不是那么容易。

我在我的应用程序中所做的是获取名为 sizeCategory 的环境变量,并根据该系统变量的值调整我的字体。

它应该也适合你。在您看来,您将在结构中添加环境变量。然后,如果您知道 .accessibilityExtraExtraLarge 破坏了您的布局,您可以这样调整它:

struct ContentView: View {
    @Environment(\.sizeCategory) var sizeCategory

    var body: some View {
       Text("Hello World")
         .font(sizeCategory == .accessibilityExtraExtraLarge ?
           .custom("Helvetica", size: 23, relativeTo: .headline) :      
           .custom("Helvetica", size: 33, relativeTo: .headline))
         .minimumScaleFactor(0.5)
    }
}

我没有你的完整代码来测试,但我会把它添加到你的函数中,它应该可以工作:

func getDigitalXFontOfSize(size s : CGFloat) -> Font {
    if font(sizeCategory == .accessibilityExtraExtraLarge {
        return Font.custom("DigitalX", size: s - 10)
    } else {
        return Font.custom("DigitalX", size: s)
}

希望对您有所帮助。我想在函数内部使用 switch 语句也是一个好主意!

这是对我有用的,

Text("Hello")
            .font((sizeCategory == .extraExtraExtraLarge || sizeCategory == .extraExtraLarge) ?
                       .custom("Helvetica", size: 110) :
                       .custom("Helvetica", size: 130))
            .minimumScaleFactor(0.5)
            .foregroundColor(.white)

如果有人正在寻找固定大小的系统字体(比如我):

.font(.system(size: 8))

(工作于 iOS 14,我不知道 13)

Can I turn off Dynamic Type support […] Can I disable Dynamic Type for specific Text views that I use in the app?

禁用 Dynamic Type 功能的最佳方法是避免使用文本样式
但是,对于您的情况,我强烈建议在不使用其全部功能的情况下考虑此功能 (您可能有一天会需要它,谁知道呢?)

除了@multitudes 接受的答案之外,展示 Dynamic Type 功能本身如何在不被停用的情况下提供这种结果似乎很有趣。

iOS 15 介绍了 new content size category limits 其目标是 设置最小和最大尺寸 Dynamic Type 特征:

⚠️但是建议在WWDC 2021 video中说明的特定情况下使用它:⚠️

Please do not use this API to unduIy limit text size. These settings serve an extremely important function, and it’s paramount that your app’s functionality is all available, and everything is legible, to people using the highest text size setting.

最后,我建议看一下 this interesting article,它描述了如何在需要时限制 Dynamic Type 大小。

终于找到了将UIFont转为Font的解决方案。我已经测试过了,它可以在我的设备上运行。

您可以在 iOS13 及更高版本上使用此代码。

extension Font {
    static let fontName = "Quicksand-Light_Bold"
    static func quickSand(size: CGFloat) -> Font {
        if let uifont =  UIFont(name: fontName, size: size) {
            return Font(uifont as CTFont)
        }
        return Font.custom(fontName, size: size)
    }
}