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

SwiftUI:如何为ViewThatFits内部的视图切换添加动画?

为ViewThatFits内部视图切换添加动画效果的实现方案

问题描述

希望为ViewThatFits内部的视图切换添加过渡、匹配几何效果等动画。当前拖动滑块调整ViewThatFits高度时,视图会在临界值处无动画切换,示例代码如下:

import SwiftUI

struct ContentView: View {
    @State private var height: CGFloat = 100.0
    
    var body: some View {
        VStack {
            Spacer()
            Slider(value: $height, in: 10.0...100.0, step: 1.0)
            Spacer()
            ViewThatFits {
                Rectangle()
                    .fill(.red)
                    .frame(height: 70.0)
                Rectangle()
                    .fill(.blue)
                    .frame(height: 30.0)
            }
            .frame(height: height)
            Spacer()
        }
    }
}

#Preview {
    ContentView()
}

可行实现方案

方案一:手动跟踪适配状态 + 过渡动画

ViewThatFits的自动切换逻辑无法直接附加动画,因此可以手动判断容器高度与视图高度的关系,通过状态变量控制视图显示,并添加过渡动画:

import SwiftUI

struct ContentView: View {
    @State private var height: CGFloat = 100.0
    @State private var showRedView = true // 跟踪当前显示的视图
    
    var body: some View {
        VStack {
            Spacer()
            Slider(value: $height, in: 10.0...100.0, step: 1.0)
                .onChange(of: height) { newValue in
                    // 根据容器高度判断显示视图,用withAnimation触发动画
                    withAnimation(.easeInOut(duration: 0.3)) {
                        showRedView = newValue >= 70
                    }
                }
            Spacer()
            // 手动切换视图并添加过渡效果
            if showRedView {
                Rectangle()
                    .fill(.red)
                    .frame(height: 70.0)
                    .transition(.scale.combined(with: .opacity))
            } else {
                Rectangle()
                    .fill(.blue)
                    .frame(height: 30.0)
                    .transition(.scale.combined(with: .opacity))
            }
            .frame(height: height)
            Spacer()
        }
    }
}

#Preview {
    ContentView()
}

方案二:使用matchedGeometryEffect实现几何匹配动画

如果需要两个视图切换时的大小、位置平滑过渡,可以结合matchedGeometryEffect实现连贯的视觉效果:

import SwiftUI

struct ContentView: View {
    @State private var height: CGFloat = 100.0
    @State private var showRedView = true
    private let shapeID = UUID() // 共享的几何匹配标识
    
    var body: some View {
        VStack {
            Spacer()
            Slider(value: $height, in: 10.0...100.0, step: 1.0)
                .onChange(of: height) { newValue in
                    withAnimation(.easeInOut(duration: 0.3)) {
                        showRedView = newValue >= 70
                    }
                }
            Spacer()
            ZStack {
                // 始终渲染两个视图,仅显示目标视图,配合几何匹配实现平滑过渡
                if showRedView {
                    Rectangle()
                        .fill(.red)
                        .frame(height: 70.0)
                        .matchedGeometryEffect(id: shapeID, in: .global)
                } else {
                    Rectangle()
                        .fill(.blue)
                        .frame(height: 30.0)
                        .matchedGeometryEffect(id: shapeID, in: .global)
                }
            }
            .frame(height: height)
            Spacer()
        }
    }
}

#Preview {
    ContentView()
}

说明

  • 方案一逻辑简单直观,通过transition可快速实现淡入淡出、缩放等基础过渡效果。
  • 方案二利用几何匹配让两个视图共享布局信息,切换时会有自然的大小/位置过渡,适合追求连贯视觉体验的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:31:01