【发布时间】:2021-03-23 01:35:22
【问题描述】:
我有一个用于文件浏览器网格的 ZStack,当您导航到文件夹时它会添加图层。文件夹图标显示文件夹内容的预览。我在预览项目上有一个matchedGeometryEffect,以便它们可以动画到打开的文件夹中。问题是动画只在关闭文件夹时发生,而不是在打开时发生。
(我知道这段代码还不能推广到包含更多内容的文件夹。如果我能让这些动画正常工作,我会做到这一点。
很抱歉一次转储大量代码,但一切都应该在这里,以便它可以在项目中试用。
struct File: Hashable {
var symbol: String?
var name: String
var contents: [File]? = nil
}
struct GridNavNew: View {
@Namespace private var ns
static var files: [File] = [
File(name: "Folder", contents: [
File(symbol: "cloud", name: "Cloudy"),
File(symbol: "cloud.hail", name: "Hail"),
File(symbol: "cloud.snow", name: "Snow"),
File(symbol: "cloud.fog", name: "Fog")
]),
File(symbol: "cube", name: "Cube"),
File(symbol: "books.vertical", name: "Books")
]
static let root = File(symbol: nil, name: "/", contents: files)
@State private var path: [File] = [root]
var body: some View {
ZStack {
// This exists because otherwise the transition doesn't play on the way out
// See https://sarunw.com/posts/how-to-fix-zstack-transition-animation-in-swiftui/
Text("A")
.opacity(0)
.zIndex(1)
ForEach(Array(path.enumerated()), id: \.offset) { index, dir in
NavigationView {
if let content = dir.contents {
ScrollView {
LazyVGrid(columns: [GridItem(), GridItem()]) {
ForEach(content, id: \.self) { file in
Button {
withAnimation {
path.append(file)
}
} label: {
FileCell(file: file,
onTop: path.last == dir,
ns: ns)
// .animation(.default)
}
}
}
.padding()
}
.navigationTitle(dir.name)
.toolbar {
ToolbarItem(placement: .navigation) {
if path.first != dir {
Button("Back") {
withAnimation {
path.removeLast()
}
}
}
}
}
}
}
.transition(.move(edge: .trailing))
}
}
.listStyle(PlainListStyle())
}
}
struct FileCell: View {
var file: File
var compact = false
var onTop: Bool
var ns: Namespace.ID
private func previewGrid(_ contents: [File]) -> some View {
LazyVGrid(columns: [GridItem(), GridItem()]) {
ForEach(contents, id: \.self) { file in
FileCell(file: file, compact: true, onTop: onTop, ns: ns)
}
}
}
private var icon: some View {
RoundedRectangle(cornerRadius: compact ? 10 : 20)
.aspectRatio(1, contentMode: .fill)
.foregroundColor(.accentColor)
.opacity(file.contents == nil ? 1 : 0)
.overlay(
Group {
if let symbol = file.symbol {
Image(systemName: symbol)
.resizable()
.scaledToFit()
.padding()
.foregroundColor(.primary)
} else if onTop,
let contents = file.contents {
previewGrid(contents)
}
}
)
}
var body: some View {
VStack {
icon
.matchedGeometryEffect(id: file, in: ns)
if !compact {
Text(file.name)
}
}
}
}
matchedGeometryEffect 在其body 中位于FileCell 的底部。
我认为可能导致问题的一件事是,由于.transition(.move(edge: .trailing)),在转换过程中匹配的几何图形不在屏幕上,但使用任何其他转换或根本不使用,也会出现同样的问题。
我还认为 ZStack 可能会导致问题,因为它已经在转换时出现了(请参阅 https://sarunw.com/posts/how-to-fix-zstack-transition-animation-in-swiftui/),但是为了测试而将 ZStack 更改为 VStack 并没有解决问题。
您可能还会注意到 FileCell 上已注释掉的 .animation(.default)。这确实允许在打开文件夹时进行动画转换,但是动画效果与在该行不存在时关闭文件夹的效果不匹配,并且还会导致文件夹关闭时文件单元格重复,从而导致错误- 外观动画。
编辑:我还想提一下,我没有收到 Multiple inserted views in matched geometry group 错误,所以这也不是问题。
【问题讨论】: