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

SwiftUI中如何实现文本从小尺寸到大尺寸的动画效果?

实现文本从小尺寸到大尺寸的动画解决方案

为啥原来的小到大动画跑不起来?
你写的代码里,上面那个蓝色小文本固定了16号字体,还加了.minimumScaleFactor(0.1)——这个属性只允许文本缩小,压根不支持放大。所以当要从16号动画到36号时,固定字号的限制直接卡死了放大的可能,自然出不来想要的效果。

改法一:用单视图过渡(更简洁)

直接用一个视图负责过渡,同时在上方显示新文本,逻辑更清晰:

struct AnimView: View {
    @State private var currentText = "23"
    @State private var nextText = "23"
    @State private var isAnimating = false
    @Namespace private var ns1

    var body: some View {
        VStack {
            // 上方新出现的小文本
            Text(nextText)
                .font(.system(size: 16))
                .foregroundColor(.blue)
                .opacity(isAnimating ? 1 : 0)
            
            // 负责动画的文本:从小变大+移动位置
            Text(currentText)
                .matchedGeometryEffect(id: "text", in: ns1)
                .font(.system(size: isAnimating ? 36 : 16))
                .foregroundColor(isAnimating ? .red : .blue)
                .animation(.easeInOut(duration: 0.5), value: isAnimating)
            
            Spacer().frame(height: 50)
            
            Button("Move Down") {
                // 先生成新文本
                nextText = String("\(Int.random(in: 1..<99))")
                // 触发动画
                isAnimating = true
                
                // 动画结束后重置状态,准备下一次
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    currentText = nextText
                    isAnimating = false
                }
            }
        }
        .padding()
    }
}

改法二:保留原双Text结构

如果你不想改整体结构,就把上面文本的固定字号改成动态切换,同时去掉minimumScaleFactor:

struct AnimView: View {
    @State private var textAnim = "23"
    @State private var matched = true
    @Namespace private var ns1

    var body: some View {
        VStack {
            Text(textAnim)
                .matchedGeometryEffect(id: matched ? "text" : "temp", in: ns1, isSource: !matched)
                .font(.system(size: matched ? 36 : 16)) // 随状态变字号
                .foregroundColor(matched ? .red : .blue)
                .animation(.easeInOut, value: matched)
            
            Spacer().frame(height: 50)
            
            Text(textAnim)
                .matchedGeometryEffect(id: "text", in: ns1, isSource: true)
                .font(.system(size: 36))
                .foregroundColor(.red)
                .opacity(matched ? 0 : 1) // 动画时藏起来避免重复
            
            Button("Move Down") {
                withAnimation(nil) {
                    textAnim = String("\(Int.random(in: 1..<99))")
                    matched = false
                }
                withAnimation {
                    matched = true
                }
            }
        }
    }
}

两种方案都能实现小文本平滑放大并移动到下方的效果,选哪种看你习惯。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:05:12