简体   繁体   English

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

[英]SwiftUI - How to change hierarchical position of View?

Here's a basic example of what doesn't work:这是不起作用的基本示例:

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 has no way to figure out that I think of the first Color.green and the second Color.green as the same view, so of course the animation just fades one of them out while fading the other one in at the new location. SwiftUI 无法弄清楚我认为第一个Color.green和第二个Color.green是同一个视图,所以当然动画只是淡出其中一个,同时在新位置淡入另一个。 I'm looking for the way to indicate to SwiftUI that these are the same view, and to animate it to the new location.我正在寻找一种方法来向 SwiftUI 表明这些是相同的视图,并将其动画化到新位置。 I discovered the .id() modifier with great excitement because I believed that it would give me the effect that I want:我非常兴奋地发现了.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") }
    }
}

This, unfortunately, does not work either.不幸的是,这也不起作用。 I'm unbelievably excited about SwiftUI, but it seems to me that the ability to change the structure of the view hierarchy while preserving view identity is quite important.我对 SwiftUI 感到难以置信的兴奋,但在我看来,在保留视图标识的同时更改视图层次结构的能力非常重要。 The actual use case which prompted me to think about this is that I have a handful of views which I'm trying to create a fan animation for.促使我考虑这一点的实际用例是,我有一些视图,我正在尝试为其创建粉丝动画。 The simplest way would be to have the items in a ZStack in one state so that they are all on top of each other, and then to have them in a VStack in the fanned out state, so that they're vertically spread out and all visible.最简单的方法是让ZStack中的项目处于一种状态,以便它们都在彼此的顶部,然后将它们置于VStack中的扇出状态,以便它们垂直展开并且所有可见的。 Changing from a ZStack to a VStack of course counts as a change to the structure and therefore all continuity between the states is lost and everything just cross fades.ZStack更改为VStack当然算作对结构的更改,因此状态之间的所有连续性都丢失了,一切都只是交叉淡入淡出。 Does anyone know what to do about this?有谁知道该怎么办?

You can do this with SwiftUI 2 introduced in iOS 14 / macOS 10.16:您可以使用 iOS 14 / macOS 10.16 中引入的 SwiftUI 2 执行此操作:

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

I think I have the animation part of your question down, but unfortunately, I don't think it will keep the same instance of the view.我想我已经解决了您问题的动画部分,但不幸的是,我认为它不会保留视图的相同实例。 I tried taking green out into a variable to see if that works, but if I understand SwiftUI correctly, that doesn't mean the same instance of the view will be shared in two places.我尝试将green带入一个变量中以查看它是否有效,但是如果我正确理解 SwiftUI,这并不意味着将在两个地方共享相同的视图实例。

What I'm doing is adding a transition when the green view is added/removed.我正在做的是在添加/删除绿色视图时添加过渡。 This way, the view moves to the location of its replacement before disappearing.这样,视图会在消失之前移动到其替换位置。

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())
            }
        }
    }
}

This solution is quick-and-dirty and uses hard-coded values based on the iPhone 6/7/8 portrait screen size此解决方案快速而肮脏,并使用基于 iPhone 6/7/8 纵向屏幕尺寸的硬编码值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM