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

SwiftUI文本子串动画:如何保持统一字号并支持自动换行?

SwiftUI 统一文本字号并保留切换动画解决方案

你的问题根源在于:每个独立的Text组件都有自己的缩放逻辑,当空间不足时会各自独立缩放,导致字号不一致。以下是两种直接可行的解决方法:


方案一:合并为单个Text(推荐,支持自动换行+统一字号)

将静态文本和动态文本拼接成一个完整的Text组件,让所有文本共享同一布局上下文,彻底解决字号不一致问题,同时保留动态部分的切换动画。

import SwiftUI

struct ContentView: View {
    let array = ["lecture", "conversation", "meeting"]
    @State private var currentIndex = 0
    @State private var currentWord = ""
    
    // 使用SwiftUI原生定时器,适配生命周期
    private let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()

    var body: some View {
        VStack {
            // 拼接为单个完整Text,确保字号、缩放、换行规则统一
            (Text("Transform ")
            + Text(currentWord)
                .transition(.opacity.combined(with: .scale)) // 淡入淡出+缩放动画
            + Text(" to Quick Note"))
                .font(.title)
                .lineLimit(nil) // 允许自动换行
                .minimumScaleFactor(0.5) // 整体缩放,而非单个Text独立缩放
                .padding()
        }
        .onReceive(timer) { _ in
            withAnimation(.easeInOut(duration: 1)) {
                currentIndex = (currentIndex + 1) % array.count
                currentWord = array[currentIndex]
            }
        }
        .onAppear {
            currentWord = array[0]
        }
    }
}

#Preview {
    ContentView()
}

关键改动

  • 合并所有Text为一个拼接组件,确保所有文本共享相同的字号、缩放和换行规则
  • 用Timer.publish替代原生Timer,避免内存泄漏,适配SwiftUI生命周期
  • 用withAnimation包裹状态更新,确保动态文本切换时有流畅动画
  • 移除单个Text的lineLimit(1),允许整体文本自动换行

方案二:保持HStack结构但统一缩放逻辑

如果需要保留HStack布局,可以通过绑定统一的缩放因子,让所有Text同步缩放:

import SwiftUI

struct ContentView: View {
    let array = ["lecture", "conversation", "meeting"]
    @State private var currentIndex = 0
    @State private var currentWord = ""
    @ScaledMetric(relativeTo: .title) private var fontSize = 1
    
    private let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()

    var body: some View {
        VStack {
            HStack(alignment: .firstTextBaseline, spacing: 4) {
                Text("Transform")
                    .font(.title.scale(fontSize))
                    .lineLimit(nil)
                
                Text(currentWord)
                    .font(.title.scale(fontSize))
                    .transition(.opacity)
                    .lineLimit(nil)
                
                Text("to Quick Note")
                    .font(.title.scale(fontSize))
                    .lineLimit(nil)
            }
            .padding()
            .minimumScaleFactor(0.5)
            .dynamicTypeSize(...DynamicTypeSize.accessibility1)
        }
        .onReceive(timer) { _ in
            withAnimation(.easeInOut(duration: 1)) {
                currentIndex = (currentIndex + 1) % array.count
                currentWord = array[currentIndex]
            }
        }
        .onAppear {
            currentWord = array[0]
        }
    }
}

// 扩展Font支持统一缩放
extension Font {
    func scale(_ factor: CGFloat) -> Font {
        self.modifier(FontScaleModifier(scaleFactor: factor))
    }
}

struct FontScaleModifier: ViewModifier {
    let scaleFactor: CGFloat
    func body(content: Content) -> some View {
        content.scaleEffect(scaleFactor)
    }
}

#Preview {
    ContentView()
}

说明

  • 通过@ScaledMetric绑定统一缩放因子,确保所有Text同步缩放
  • 用HStack(alignment: .firstTextBaseline)保证文本基线对齐,避免错位
  • 保留HStack结构的同时,解决字号不一致问题

内容的提问来源于stack exchange,提问作者Cheok Yan Cheng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:36:02