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

SwiftUI雨滴文字动画性能优化:降低CPU占用率

问题描述

我非常喜欢应用后台运行的这款动画效果,但它目前的CPU占用极高。请问能否在保留其动态移动和透明度变化效果的前提下,降低动画对CPU的消耗?简言之:如何重构这段动画代码以减轻性能负担?

我已尝试仅在视图首次加载时运行动画、减少行数、缩短动画时长,但遗憾的是CPU占用仍然很高。

原代码

import SwiftUI

struct RainAnimationView: View {
    var rows = 17
    @State var textContent = Array("bokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokwormbokworm").map({ String($0) }).shuffled()
    var randomAnimationDuration = 15.0...20.5
    @State var animateRain: Bool = false
    
    func shuffleTextContent() {
        textContent.shuffle()
    }
    
    let animation = Animation.easeIn(duration: Double.random(in: 15.0...20.5)).repeatForever(autoreverses: false)
    
    @Binding var shareVar: Bool {
        didSet {
            withAnimation(.easeIn(duration: Double.random(in: randomAnimationDuration)).repeatForever(autoreverses: false)) {
                animateRain = true }
        }
    }
    
    @State private var opacity: Double = 0.0
    
    var body: some View {
        GeometryReader { geometry in
            HStack() {
                Spacer()
                ForEach(0..<rows, id: \.self) { index in
                    VStack {
                        Spacer()
                        ForEach(0..<textContent.count, id: \.self) { index in
                            Text(textContent[index])
                                .foregroundColor(Color.brown)
                                .font(.custom("AmericanTypewriter", size: 17))
                            Spacer()
                        }
                    }
                    .offset(y: -geometry.size.height - 100)
                    .offset(x: 0, y: animateRain ? 2*geometry.size.height : -geometry.size.height)
                    .rotation3DEffect(animateRain ? .degrees(49) : .degrees(1), axis: (x: 0, y: 1, z: 0))
                    .opacity(animateRain ? 1.0 : 0.0)
                    .animation(Animation.easeInOut(duration: Double.random(in: randomAnimationDuration)).repeatForever(autoreverses: true), value: animateRain)
                }
            }
            .frame(width: geometry.size.width, height: geometry.size.height + 200)
            .clipped()
            .onAppear() { DispatchQueue.main.async { withAnimation(animation) {
                animateRain = false
                withAnimation(animation) {
                    animateRain = true
                }
            }}}
            .ignoresSafeArea(edges: .top)
        }
    }
}
优化方案

1. 核心优化思路

原代码性能瓶颈集中在过多独立视图渲染、冗余动画属性计算、重复布局逻辑三点,针对这些问题做针对性重构:

  • 合并视图层级:将每行的单个字符Text合并为整行文本,大幅减少视图数量
  • 简化动画属性:移除高开销的3D旋转(如需保留可替换为2D旋转),减少同时动画的属性数量
  • 预计算静态内容:初始化时生成所有行的随机文本,避免运行时频繁数组操作
  • 清理冗余代码:移除未使用的状态变量与重复动画实例

重构后的代码

import SwiftUI

struct OptimizedRainAnimationView: View {
    var rows = 17
    @State private var rowTexts: [String] = []
    let randomAnimationDuration = 15.0...20.5
    @State private var animateRain = false
    @Binding var shareVar: Bool
    
    init(shareVar: Binding<Bool>) {
        self._shareVar = shareVar
        // 预生成每行的随机文本字符串,减少视图数量
        let baseText = "bokworm".repeating(count: 10)
        self.rowTexts = (0..<rows).map { _ in baseText.shuffled() }
    }
    
    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: geometry.size.width / CGFloat(rows + 1)) {
                ForEach(0..<rows, id: \.self) { index in
                    Text(rowTexts[index])
                        .foregroundColor(.brown)
                        .font(.custom("AmericanTypewriter", size: 17))
                        .lineLimit(nil)
                        .multilineTextAlignment(.center)
                        .frame(height: geometry.size.height * 2)
                        .offset(y: animateRain ? geometry.size.height : -geometry.size.height)
                        .opacity(animateRain ? 1.0 : 0.0)
                        // 统一动画实例,减少重复计算
                        .animation(
                            Animation.easeInOut(duration: Double.random(in: randomAnimationDuration))
                                .repeatForever(autoreverses: true),
                            value: animateRain
                        )
                }
            }
            .frame(width: geometry.size.width, height: geometry.size.height)
            .clipped()
            .onAppear { animateRain = true }
            .onChange(of: shareVar) { _ in
                animateRain = false
                withAnimation(
                    Animation.easeIn(duration: Double.random(in: randomAnimationDuration))
                        .repeatForever(autoreverses: false)
                ) {
                    animateRain = true
                }
            }
            .ignoresSafeArea(edges: .top)
        }
    }
}

// 扩展字符串辅助方法
extension String {
    func repeating(count: Int) -> String {
        String(repeating: self, count: count)
    }
    
    func shuffled() -> String {
        String(self.shuffled())
    }
}

额外性能建议

如果必须保留3D旋转效果,可以添加rotation3DEffect,但建议:

  • 降低旋转角度(比如从49度改为20度)
  • 仅在动画的特定阶段应用3D效果,而非全程开启
  • 尝试添加.drawingGroup()修饰符,将视图合并为单个图层渲染,利用GPU加速

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:25:22