3

这是一个不起作用的基本示例:

import SwiftUI

struct Test : View {
    @State var swapped = false

    var body: some View {
        if swapped { Color.green }
        Color.blue.tapAction {
            withAnimation { self.swapped.toggle() }
        }
        if !swapped { Color.green }
    }
}

SwiftUI 无法弄清楚我认为第一个Color.green和第二个Color.green视图是同一个视图,所以当然动画只是将其中一个淡出,同时在新位置淡入另一个。我正在寻找向 SwiftUI 指示这些是相同视图并将其动画化到新位置的方法。我非常兴奋地发现了这个.id()修饰符,因为我相信它会给我想要的效果:

import SwiftUI

struct Test : View {
    @State var swapped = false

    var body: some View {
        if swapped { Color.green.id("green") }
        Color.blue.tapAction {
            withAnimation { self.swapped.toggle() }
        }
        if !swapped { Color.green.id("green") }
    }
}

不幸的是,这也不起作用。我对 SwiftUI 感到难以置信的兴奋,但在我看来,在保持视图标识的同时更改视图层次结构的能力非常重要。促使我考虑这一点的实际用例是,我有一些视图,我正在尝试为其创建粉丝动画。最简单的方法是让项目处于ZStack一种状态,使它们都在彼此之上,然后让它们处于VStack扇出状态,这样它们就可以垂直展开并且全部可见。从 a 更改为ZStackaVStack当然算作结构的更改,因此状态之间的所有连续性都丢失了,一切都只是交叉淡入淡出。有谁知道该怎么做?

4

2 回答 2

0

您可以使用 iOS 14 / macOS 10.16 中引入的 SwiftUI 2 来做到这一点:

@Namespace private var animation
…
MyView.matchedGeometryEffect(id: "myID", in: animation)
于 2020-06-30T21:16:05.217 回答
-1

我想我已经把你问题的动画部分记下来了,但不幸的是,我认为它不会保留相同的视图实例。我尝试green取出一个变量来查看它是否有效,但如果我正确理解 SwiftUI,这并不意味着视图的同一个实例将在两个地方共享。

我正在做的是在添加/删除绿色视图时添加一个过渡。这样,视图会在消失之前移动到其替换位置。

struct Test : View {
    @State var swapped = false
    let green = Color.green

    var body: some View {
        HStack {
            if swapped {
                green
                    .transition(.offset(CGSize(width: 200, height: 0)))
                    .animation(.basic())
            }
            Color.blue.animation(.basic()).tapAction {
                withAnimation { self.swapped.toggle() }
            }
            if !swapped {
                green.transition(.offset(CGSize(width: -200, height: 0)))
                .animation(.basic())
            }
        }
    }
}

此解决方案既快又脏,并使用基于 iPhone 6/7/8 纵向屏幕尺寸的硬编码值

于 2019-06-14T00:32:11.003 回答