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

SwiftUI:条件修改字体粗细时界面出现卡顿问题

解决SwiftUI字体粗细切换时的卡顿问题

你的问题本质是不同字重的字体度量差异触发了布局重算,加上spring动画的放大效果,导致视觉上出现卡顿/跳动。以下是几个实用的解决办法:

1. 固定文本容器宽度(最直接有效)

不同字重的文本宽度不同,切换时会让父视图重新计算布局,这是卡顿的核心原因。给Text添加固定宽度的frame,就能避免布局变化:

Text(tab)
    .font(.system(size: 16, weight: selectedTab == tab ? .heavy : .medium, design: .rounded))
    .foregroundColor(selectedTab == tab ? .red : .blue)
    .frame(width: 60, alignment: .leading) // 根据你的文本长度调整宽度
    .onTapGesture {
        withAnimation(.spring()) {
            selectedTab = tab
        }
    }

如果想适配不同文本长度,可以提前计算所有标签的最大宽度:

private var maxTabWidth: CGFloat {
    tbs.map { tab in
        let heavyFont = UIFont.systemFont(ofSize: 16, weight: .heavy, design: .rounded)
        return tab.size(withAttributes: [.font: heavyFont]).width
    }.max() ?? 0
}

然后把frame的width设为maxTabWidth即可。

2. 优化下划线的显示逻辑

原来的if tab == selectedTab会直接添加/移除下划线视图,也会触发布局变化。改用透明度动画替代条件显示,过渡更平滑:

Rectangle()
    .foregroundColor(.red)
    .frame(width: 20, height: 1)
    .opacity(selectedTab == tab ? 1 : 0)

完整修改后的代码

struct Playground: View {
    @State private var selectedTab = "Liked"
    let tbs = ["Liked", "Reading", "Ended"]
    
    private var maxTabWidth: CGFloat {
        tbs.map { tab in
            let heavyFont = UIFont.systemFont(ofSize: 16, weight: .heavy, design: .rounded)
            return tab.size(withAttributes: [.font: heavyFont]).width
        }.max() ?? 0
    }
    
    var body: some View {
        HStack {
            ForEach(tbs, id: \.self) { tab in
                HStack {
                    VStack(alignment: .leading, spacing: 1) {
                        Text(tab)
                            .font(.system(size: 16, weight: selectedTab == tab ? .heavy : .medium, design: .rounded))
                            .foregroundColor(selectedTab == tab ? .red : .blue)
                            .frame(width: maxTabWidth, alignment: .leading)
                            .onTapGesture {
                                withAnimation(.spring()) {
                                    selectedTab = tab
                                }
                            }
                            .padding(.bottom, selectedTab != tab ? 1 : 0)
                        
                        Rectangle()
                            .foregroundColor(.red)
                            .frame(width: 20, height: 1)
                            .opacity(selectedTab == tab ? 1 : 0)
                    }
                }
                .padding(.horizontal, 5)
            }
        }
    }
}

这些修改能彻底消除字体切换时的卡顿,同时保持动画的流畅性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 04:12:08