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

SwiftUI中利用.rotation3DEffect实现多视图翻转切换

多视图圆形翻转动画实现方案(SwiftUI)

你的现有代码存在视图重复实现、状态管理繁琐的问题,导致翻转动画逻辑混乱。以下是优化后的实现,支持任意数量视图的平滑翻转切换:

核心优化点

  • 封装通用圆形视图,消除重复代码
  • 用枚举管理当前显示视图,替代大量Bool状态变量
  • 简化翻转动画逻辑,确保切换过程平滑自然

完整代码

// 通用圆形视图,统一实现样式和旋转效果
struct ColoredCircleView: View {
    let color: Color
    let text: String
    @Binding var rotationDegree: Double
    
    var body: some View {
        ZStack {
            Circle()
                .frame(width: 350, height: 350)
                .foregroundColor(color)
            Text(text)
                .foregroundColor(.black)
                .font(.title)
        }
        .rotation3DEffect(
            Angle(degrees: rotationDegree),
            axis: (x: 0, y: 1, z: 0),
            perspective: 0.2
        )
    }
}

// 枚举标记当前显示的视图
enum CurrentView {
    case teal, red, blue, yellow
}

struct ContentView: View {
    @State private var currentView: CurrentView = .teal
    @State private var rotationDegree: Double = 0
    @State private var isTransitioning = false
    
    let animationDuration: Double = 0.45
    
    // 切换视图并执行翻转动画
    func switchToView(_ newView: CurrentView) {
        guard currentView != newView, !isTransitioning else { return }
        
        isTransitioning = true
        
        // 第一步:将当前视图转到90度(不可见)
        withAnimation(.easeInOut(duration: animationDuration)) {
            rotationDegree = 90
        }
        
        // 第二步:切换视图,再将新视图转到0度
        DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
            currentView = newView
            withAnimation(.easeInOut(duration: animationDuration)) {
                rotationDegree = 0
            }
            isTransitioning = false
        }
    }
    
    var body: some View {
        VStack {
            // 根据当前状态显示对应视图
            switch currentView {
            case .teal:
                ColoredCircleView(
                    color: .systemTeal,
                    text: "Teal View!",
                    rotationDegree: $rotationDegree
                )
            case .red:
                ColoredCircleView(
                    color: .systemRed,
                    text: "Red View!",
                    rotationDegree: $rotationDegree
                )
            case .blue:
                ColoredCircleView(
                    color: .systemBlue,
                    text: "Blue View!",
                    rotationDegree: $rotationDegree
                )
            case .yellow:
                ColoredCircleView(
                    color: .systemYellow,
                    text: "Yellow View!",
                    rotationDegree: $rotationDegree
                )
            }
            
            HStack(spacing: 20) {
                // 切换按钮
                Button {
                    switchToView(.teal)
                } label: {
                    ZStack {
                        Circle()
                            .foregroundColor(.systemTeal)
                            .frame(width: 60, height: 60)
                        Text("Teal")
                            .foregroundColor(.black)
                    }
                }
                
                Button {
                    switchToView(.red)
                } label: {
                    ZStack {
                        Circle()
                            .foregroundColor(.systemRed)
                            .frame(width: 60, height: 60)
                        Text("Red")
                            .foregroundColor(.black)
                    }
                }
                
                Button {
                    switchToView(.blue)
                } label: {
                    ZStack {
                        Circle()
                            .foregroundColor(.systemBlue)
                            .frame(width: 60, height: 60)
                        Text("Blue")
                            .foregroundColor(.black)
                    }
                }
                
                Button {
                    switchToView(.yellow)
                } label: {
                    ZStack {
                        Circle()
                            .foregroundColor(.systemYellow)
                            .frame(width: 60, height: 60)
                        Text("Yellow")
                            .foregroundColor(.black)
                    }
                }
            }
            .padding(.top, 30)
        }
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

代码说明

  1. 通用视图封装:ColoredCircleView将圆形样式、文本、旋转效果统一封装,新增视图只需传入颜色和文本即可,无需重复编写布局代码。
  2. 状态管理简化:用CurrentView枚举记录当前显示的视图,替代原来的多个Bool变量,状态逻辑更清晰,避免出错。
  3. 动画逻辑优化:翻转动画分为两步:先将当前视图旋转到90度(视觉上消失),切换视图后再将新视图旋转回0度,确保过渡过程平滑自然,且同一时间只执行一次动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:35:23