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

Posted

技术标签:

【中文标题】SwiftUI - 如何更改视图的层次位置?【英文标题】:SwiftUI - How to change hierarchical position of View? 【发布时间】:2019-10-22 12:34:55 【问题描述】:

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

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 当然算作结构的更改,因此状态之间的所有连续性都丢失了,一切都只是交叉淡入淡出。有谁知道该怎么办?

【问题讨论】:

【参考方案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 纵向屏幕尺寸的硬编码值

【讨论】:

这不是问题的解决方案,它以非常硬编码的方式覆盖了 SwiftUI。他想要一种方法来告诉 SwiftUI 去做。 这对从 ZStack 到 VStack 没有帮助。显然,他在寻求一种使用布局来定位视图并为其设置动画的方法。【参考方案2】:

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

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

【讨论】:

以上是关于SwiftUI - 如何更改视图的层次位置?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如何更改 NavigationView 的色调(背景颜色)?

如何将不在根层次结构中的 SwiftUI 视图呈现为 UIImage?

SwiftUI - 状态更改后的运行功能

如何在 SwiftUI 应用生命周期中更改状态栏样式?

如何在 SwiftUI 中禁用位置动画?

@ObservedObject 更改后 SwiftUI 视图未更新