Animation SwiftUI-如何更改视图的层次位置?

Animation SwiftUI-如何更改视图的层次位置?,animation,structure,identity,swiftui,view-hierarchy,Animation,Structure,Identity,Swiftui,View Hierarchy,下面是一个不起作用的基本示例: 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

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

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中,使其呈扇形展开,使它们垂直展开并全部可见。从ZStack更改为VStack当然算作结构的更改,因此状态之间的所有连续性都会丢失,所有东西都会交叉淡出。有人知道该怎么做吗?

我想我已经记下了你问题中的动画部分,但不幸的是,我认为它不会保留视图的相同实例。我试着把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纵向屏幕大小的硬编码值

我想我已经记下了您问题的动画部分,但不幸的是,我认为它不会保留相同的视图实例。我试着把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纵向屏幕大小的硬编码值

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

@Namespace private var animation
…
MyView.matchedGeometryEffect(id: "myID", in: animation)

您可以通过iOS 14/macOS 10.16中引入的SwiftUI 2来实现这一点:

@Namespace private var animation
…
MyView.matchedGeometryEffect(id: "myID", in: animation)

这不是问题的解决方案,它以一种非常硬的编码方式覆盖SwiftUI。他想要一种方法告诉SwiftUI去做,这对从ZStack转到VStack没有帮助。很明显,他在寻求一种使用布局来定位和动画视图的方法。这不是问题的解决方案,而是以一种非常硬的编码方式覆盖SwiftUI。他想要一种方法告诉SwiftUI去做,这对从ZStack转到VStack没有帮助。很明显,他在寻求一种使用布局来定位和设置视图动画的方法。