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
相关产品推荐
相关产品推荐

