You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI基于屏幕尺寸自适应字体时多Text字号不统一如何解决

问题原因

你当前实现的fitSystemFont修饰符是每个Text组件独立读取自身所在容器的尺寸计算字号,不同Text的容器宽度、文本长度都有差异,所以各自算出的字号自然不一致。

可行解决方案

核心逻辑是先收集所有需要统一字号的文本能适配的最大可用字号,取最小值批量应用到所有文本上,保证所有文本字号统一且都能完整显示。

第一步:定义字号收集用的PreferenceKey

struct FontSizePreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = .greatestFiniteMagnitude
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        // 取所有文本可用的最小字号作为统一字号
        value = min(value, nextValue())
    }
}

第二步:改造适配字体的修饰符,支持同步字号

struct SyncFontModifier: ViewModifier {
    let lineLimit: Int
    let maxFontSize: CGFloat
    @Binding var finalFontSize: CGFloat
    
    func body(content: Content) -> some View {
        content
            // 先设置最大字号计算缩放比例
            .font(.system(size: maxFontSize))
            .lineLimit(lineLimit)
            .minimumScaleFactor(0.01)
            .background(
                GeometryReader { geo in
                    // 计算当前文本在容器内可以完整显示的最大字号
                    let textStr = (content as? Text ?? Text("")).string
                    let attributes: [NSAttributedString.Key: Any] = [
                        .font: UIFont.systemFont(ofSize: maxFontSize)
                    ]
                    let nativeTextSize = textStr.size(withAttributes: attributes)
                    let scale = min(geo.size.width / nativeTextSize.width, geo.size.height / nativeTextSize.height)
                    let availableFontSize = maxFontSize * scale
                    
                    Color.clear.preference(key: FontSizePreferenceKey.self, value: availableFontSize)
                }
            )
            // 应用统一计算后的最终字号
            .font(.system(size: finalFontSize))
    }
}

extension View {
    func syncFont(lineLimit: Int = 1, maxFontSize: CGFloat = 30, finalFontSize: Binding<CGFloat>) -> some View {
        self.modifier(SyncFontModifier(lineLimit: lineLimit, maxFontSize: maxFontSize, finalFontSize: finalFontSize))
    }
}

第三步:业务页面改造使用

struct TrackLoanView: View {
    // 存储所有文本统一使用的最终字号
    @State private var unifiedFontSize: CGFloat = 30
    
    var body: some View {
        NavigationView{
            ZStack{
                Color.yellow.edgesIgnoringSafeArea(.all)
                VStack{
                    ScrollView{
                        VStack{
                            HStack{
                                VStack{
                                    Text("KARTHI")
                                        .syncFont(finalFontSize: $unifiedFontSize)
                                    Text("7502875893")
                                        .syncFont(finalFontSize: $unifiedFontSize)
                                }
                                Spacer()
                                HStack{
                                    VStack{
                                        Image(systemName: "menucard")
                                        Text("REPORT")
                                            .syncFont(finalFontSize: $unifiedFontSize)
                                    }
                                    VStack{
                                        Image(systemName: "menucard")
                                        Text("DOCUMENTS")
                                            .syncFont(finalFontSize: $unifiedFontSize)
                                    }
                                    VStack{
                                        Image(systemName: "menucard")
                                        Text("CONTACT")
                                            .syncFont(finalFontSize: $unifiedFontSize)
                                    }
                                    
                                }
                            }
                        }.padding()
                        // 接收所有文本上报的可用字号,更新统一字号
                        .onPreferenceChange(FontSizePreferenceKey.self) { value in
                            unifiedFontSize = value
                        }
                    }.background(Color.orange)
                }.background(Color.gray).padding(.all)
            }.navigationTitle("Track Loan")
        }
    }
}
补充说明

如果需要适配自定义字体,只需要把UIFont.systemFont替换为对应自定义字体的构造方法即可;如果有多个独立的文本组需要分别统一字号,给每个组单独定义一个@State字号变量即可,不会互相干扰。

内容的提问来源于stack exchange,提问作者karthikeyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 03:24:03