.matchedGeometryEffect 不适用于 ForEach

问题描述 投票:0回答:1

我正在尝试显示一个

ForEach
项目,它可能会转换成一个假的工作表视图,但我不知道我做错了什么,因为
ForEach
只是将每个项目显示在彼此之上。

这是一张它应该是什么样子的图片(如果我删除

.matchedGeometryEffect
,它就会这样): how it should look like

但这就是它的样子,当我想使用

.matchedGeometryEffect
时: enter image description here

该效果确实有效,但基本上仅适用于顶部的此项,因为它是唯一可点击的。

这是我的代码:

import SwiftUI

struct Item: Identifiable {
    let id = UUID().uuidString
    let title: String
    let subtitle: String
    let image: ImageResource
}

struct ContentView: View {
    
    @Namespace var sheet
    private var rectangleId = "Rectangle"
    private var titleId = "Title"
    private var subtitleId = "Subtitle"
    
    @State var isExpanded: Bool = false
    
    @State private var selected: Item?
    
    let items: [Item] = [
        .init(title: "Test 1", subtitle: "testing stuff 1", image: .test),
        .init(title: "Test 2", subtitle: "testing stuff 2", image: .test1),
        .init(title: "Test 3", subtitle: "testing stuff 3", image: .test2),
        .init(title: "Test 4", subtitle: "testing stuff 4", image: .test3),
        .init(title: "Test 5", subtitle: "testing stuff 5", image: .test4),
    ]
    
    var body: some View {
        NavigationStack {
            ZStack {
                if isExpanded {
                    sheetView(item: selected!)
                } else {
                    ScrollView {
                        ForEach(items, id: \.id) { item in
                            normalView(item: item)
                        }
                    }
                    .padding()
                }
            }
        }
    }
    
    @ViewBuilder
    func normalView(item: Item) -> some View {
        Image(item.image)
            .resizable()
            .scaledToFit()
            .clipShape(RoundedRectangle(cornerRadius: 12))
            .matchedGeometryEffect(id: rectangleId, in: sheet)
            .onTapGesture {
                withAnimation {
                    self.selected = item
                    isExpanded.toggle()
                }
            }
            .overlay(alignment: .bottomLeading) {
                VStack(alignment: .leading) {
                    Text(item.title)
                        .font(.title)
                        .matchedGeometryEffect(id: titleId, in: sheet)
                    Text(item.subtitle)
                        .matchedGeometryEffect(id: subtitleId, in: sheet)
                }
                .foregroundStyle(.white)
                .padding()
            }
    }
    
    @ViewBuilder
    func sheetView(item: Item) -> some View {
        ScrollView {
            Image(item.image)
                .resizable()
                .scaledToFit()
                .matchedGeometryEffect(id: rectangleId, in: sheet)
                .overlay(alignment: .bottomLeading) {
                    VStack(alignment: .leading) {
                        Text(item.title)
                            .font(.title)
                            .matchedGeometryEffect(id: titleId, in: sheet)
                        Text(item.subtitle)
                            .matchedGeometryEffect(id: subtitleId, in: sheet)
                    }
                    .foregroundStyle(.white)
                    .padding()
                }
            
            ForEach(0..<50) { item in
                Text("New test text lol \(item)")
            }
        }
        .ignoresSafeArea(edges: .top)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button {
                    withAnimation {
                        isExpanded.toggle()
                    }
                } label: {
                    Image(systemName: "plus.circle.fill")
                }
            }
        }
    }
}

#Preview {
    ContentView()
}

swiftui matchedgeometryeffect
1个回答
0
投票

这不起作用,因为你总是显示相同的

matchedGeometryEffect
id,这样的东西应该可以解决你的问题:

import SwiftUI

struct Item: Identifiable {
    let id = UUID().uuidString
    let title: String
    let subtitle: String
    let image: ImageResource
}

struct ContentView: View {
    
    @Namespace var sheet
    private var rectangleId = "Rectangle"
    private var titleId = "Title"
    private var subtitleId = "Subtitle"
    
    @State var isExpanded: Bool = false
    
    @State private var selected: Item?
    
    let items: [Item] = [
        .init(title: "Test 1", subtitle: "testing stuff 1", image: .test),
        .init(title: "Test 2", subtitle: "testing stuff 2", image: .test1),
        .init(title: "Test 3", subtitle: "testing stuff 3", image: .test2),
        .init(title: "Test 4", subtitle: "testing stuff 4", image: .test3),
        .init(title: "Test 5", subtitle: "testing stuff 5", image: .test4),
    ]
    
    var body: some View {
        NavigationStack {
            ZStack {
                if isExpanded {
                    sheetView(item: selected!)
                } else {
                    ScrollView {
                        ForEach(items, id: \.id) { item in
                            normalView(item: item)
                        }
                    }
                    .padding()
                }
            }
        }
    }
    
    @ViewBuilder
    func normalView(item: Item) -> some View {
        Image(item.image)
            .resizable()
            .scaledToFit()
            .clipShape(RoundedRectangle(cornerRadius: 12))
            // Differentiate items
            .matchedGeometryEffect(id: item.id + "background", in: sheet)
            .onTapGesture {
                withAnimation {
                    self.selected = item
                    isExpanded.toggle()
                }
            }
            .overlay(alignment: .bottomLeading) {
                VStack(alignment: .leading) {
                    Text(item.title)
                        .font(.title)
                        .matchedGeometryEffect(id: item.id + "title", in: sheet)
                    Text(item.subtitle)
                        .matchedGeometryEffect(id: item.id + "subtitle", in: sheet)
                }
                .foregroundStyle(.white)
                .padding()
            }
    }
    
    @ViewBuilder
    func sheetView(item: Item) -> some View {
        ScrollView {
            Image(item.image)
                .resizable()
                .scaledToFit()
                .matchedGeometryEffect(id: item.id + "background", in: sheet)
                .overlay(alignment: .bottomLeading) {
                    VStack(alignment: .leading) {
                        Text(item.title)
                            .font(.title)
                            .matchedGeometryEffect(id: item.id + "title", in: sheet)
                        Text(item.subtitle)
                            .matchedGeometryEffect(id: item.id + "subtitle", in: sheet)
                    }
                    .foregroundStyle(.white)
                    .padding()
                }
            
            ForEach(0..<50) { item in
                Text("New test text lol \(item)")
            }
        }
        .ignoresSafeArea(edges: .top)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button {
                    withAnimation {
                        isExpanded.toggle()
                    }
                } label: {
                    Image(systemName: "plus.circle.fill")
                }
            }
        }
    }
}

#Preview {
    ContentView()
}
© www.soinside.com 2019 - 2024. All rights reserved.