SwiftUI - 同时动画视图转换和位置更改

ahe*_*eze 22 ios swift swiftui swiftui-animation

我有一个黄色容器,里面有绿色的视图。我想移动容器,同时隐藏/显示内部绿色视图,并带有动画。目前,我正在使用.offset运动,以及if绿色视图过渡的声明。

问题是,虽然黄色容器移动,但绿色视图却没有。它只是在目标偏移处淡入和淡出。我希望它也沿着黄色容器移动。

这就是我目前得到的 这就是我要的
黄色容器左右移动,而绿色内部视图淡入和淡出。 绿色景观保持在右侧 黄色容器与绿色内部视图一起左右移动,绿色内部视图也会淡入和淡出。

这是我的代码:

struct ContentView: View {
    @State var showingSubview = false
    
    var body: some View {
        VStack {
            Button("Show Subview") {
                withAnimation(.easeInOut(duration: 2)) {
                    showingSubview.toggle()
                }
            }
            
            if showingSubview {
                Text("Subview")
                    .padding()
                    .background(Color.green)
            }
        }
        .padding()
        .background(Color.yellow)
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}
Run Code Online (Sandbox Code Playgroud)

当绿色视图淡入和淡出时,如何使绿色视图与黄色容器一起移动?最好,我想继续使用iforswitch语句进行插入/删除。

ahe*_*eze 24

一年后找到了解决方案,非常简单 \xe2\x80\x94 只需添加.scaleEffect(1)

\n
.clipped() /// prevent the green view from overflowing\n.scaleEffect(1) /// the magic modifier!\n
Run Code Online (Sandbox Code Playgroud)\n

这是一个更干净的解决方案,不涉及设置自定义框架或其他内容。此外,它还可以与ifswitch语句一起使用!

\n

Yellow container moves right and left along with the green inner view, which also fades in and out.

\n

我不完全确定为什么.scaleEffect(1)有效,但它与 SwiftUI 组合视图的方式有关。我认为修改器使 SwiftUI 将其渲染为一个新组?如果有人知道为什么,我将不胜感激。

\n

这是完整的代码:

\n
struct ContentView: View {\n    @State var showingSubview = false\n\n    var body: some View {\n        VStack {\n            Button("Show Subview") {\n                withAnimation(.easeInOut(duration: 2)) {\n                    showingSubview.toggle()\n                }\n            }\n\n            if showingSubview {\n                Text("Subview")\n                    .padding()\n                    .background(Color.green)\n            }\n        }\n        .padding()\n        .background(Color.yellow)\n        .clipped() /// 1.\n        .scaleEffect(1) /// 2.\n        .offset(x: showingSubview ? 150 : 0, y: 0)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

  • 谢谢迈克。为了那些无法访问 WWDC Digital Lounge 的其他人的利益,Apple 工程师提到:“发生这种情况是因为动画默认发生在容器内的子级级别。当新的子级出现在中间时,过渡,它出现在其目标位置。作为解决方法,您可以将 .transformEffect(.identity)` 修饰符应用于容器,这将导致布局动画发生在容器级别。这应该为您提供你所追求的行为。” (6认同)
  • 今年的 WWDC Digital Lounge 上也提出了类似的问题,一位 Apple 工程师的回答是你应该使用“.transformEffect(.identity)”。`.scaleEffect(1)` 似乎做了完全相同的事情,但可能更不直观。 (5认同)

Geo*_*e_E 7

您只需在动画时更改高度即可。

代码版本#1

它不会褪色并出现在黄色矩形内。

代码:

struct ContentView: View {
    @State var showingSubview = false

    var body: some View {
        VStack(spacing: 0) {
            Button("Show Subview") {
                withAnimation(.easeInOut(duration: 2)) {
                    showingSubview.toggle()
                }
            }

            Text("Subview")
                .padding()
                .background(Color.green)
                .padding(.top)
                .frame(height: showingSubview ? nil : 0, alignment: .top)
                .clipped()
        }
        .padding()
        .background(Color.yellow)
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}
Run Code Online (Sandbox Code Playgroud)

结果#1

结果1

代码版本#2

此版本将淡出并出现在底部边缘,如 GIF 所示。

代码:

struct ContentView: View {
    @State var showingSubview = false

    var body: some View {
        VStack(spacing: 0) {
            Button("Show Subview") {
                withAnimation(.easeInOut(duration: 2)) {
                    showingSubview.toggle()
                }
            }

            Text("Subview")
                .padding()
                .background(Color.green)
                .padding(.top)
                .frame(height: showingSubview ? nil : 0, alignment: .top)
                .padding(.bottom)
                .background(Color.yellow)
                .clipped()
                .opacity(showingSubview ? 1 : 0)
        }
        .padding([.horizontal, .top])
        .background(Color.yellow)
        .padding(.bottom)
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}
Run Code Online (Sandbox Code Playgroud)

结果#2

结果2