如何将 LazyVGrid 单元格与 TabView 中相应的全屏图像连接起来 (Xcode 13, iOS15)

How to connect LazyVGrid cells with the corresponding full screen images in a TabView (Xcode 13, iOS15)

从相应的选项卡缩小时,我很难匹配正确的网格单元格。

刚开始学习,我一定要再看几个教程。如果你想在这里伸出援手,提前谢谢你。

这是代码:

型号

struct Thumbnail: Identifiable {
    let id = UUID()
    var name: String
}

struct Wallpaper: Identifiable {
    var id = UUID()
    var name: String
}

let thumbnailSet = (1...50).map { Thumbnail(name: "iridisfera-thumbnail-\([=12=])") }
let wallpaperSet = (1...50).map { Wallpaper(name: "iridisfera-wallpaper-\([=12=])") }

图库 (我删除了我的 selectedTab 实验,所以你可以直接插入你的代码)

struct GalleryView: View {
    @Namespace var namespace
    @State private var fullScreen: Int? = nil
    @State private var selectedTab = 0
    
    let columns = [GridItem(.flexible(), spacing: 2), GridItem(.flexible())]
    
    var body: some View {
        ZStack {
            // MARK: GRID VIEW
            ScrollView(showsIndicators: false) {
                LazyVGrid(columns: columns, spacing: 2) {
                    ForEach(thumbnailSet.indices) { index in
                        
                        let fullscreenIndex = fullScreen
                        if index == fullscreenIndex {
                            Color.clear
                        } else {
                            Image(thumbnailSet[index].name)
                                .resizable()
                                .aspectRatio(0.5, contentMode: .fit)
                                .matchedGeometryEffect(id: index, in: namespace)
                                .onTapGesture {
                                    withAnimation(.interpolatingSpring(mass: 0.2, stiffness: 34, damping: 4)) {fullScreen = index}
                                }
                        }
                    }
                }
            }
            .ignoresSafeArea()
            
            // MARK: FULL SCREEN VIEW
            if let fullscreenIndex = fullScreen {
                TabView(selection: $selectedTab) {
                    ForEach(wallpaperSet.indices) { index in
                        
                        Image(wallpaperSet[index].name)
                            .resizable()
                            .ignoresSafeArea()
                            .scaledToFill()
                    }
                }
                .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
                .matchedGeometryEffect(id: fullscreenIndex, in: namespace)
                .ignoresSafeArea()
                .zIndex(1)
                .onTapGesture {
                    withAnimation(.interpolatingSpring(mass: 0.1, stiffness: 28, damping: 4)) {fullScreen = nil}
                }
            }
        }
    }
}

此代码显示了一般方法。 TabView 必须位于单独的结构中,因此可以使用已经 selected 的选项卡对其进行初始化。 TabView 中的图像需要 .tag() 才能为 selection 识别它们。
它还不能很好地工作,因为你的图像无法识别,但它应该给你方向。单独使用索引是不安全的,所以你应该把它们放在一个可识别的结构中,并通过 id select。

struct GalleryView: View {
    
    @Namespace var namespace
    @State private var fullScreen: Int? = nil
    
    let columns = [GridItem(.flexible(), spacing: 2), GridItem(.flexible())]
    
    var body: some View {
        ZStack {
            // MARK: GRID VIEW
            ScrollView(showsIndicators: false) {
                LazyVGrid(columns: columns, spacing: 2) {
                    ForEach(thumbnailSet.indices) { index in
                        
                        if index == fullScreen {
                            Color.clear
                        } else {
                            Image(thumbnailSet[index].name)
                                .resizable()
                                .aspectRatio(1, contentMode: .fill)
                                .matchedGeometryEffect(id: index, in: namespace)
                                .onTapGesture {
                                    withAnimation {
                                        fullScreen = index
                                    }
                                }
                        }
                    }
                }
            }
            .ignoresSafeArea()
            
            // MARK: FULL SCREEN VIEW
            if fullScreen != nil {
                FullscreenTabView(selectedImage: $fullScreen, ns: namespace)
            }
        }
    }
}


struct FullscreenTabView: View {
    
    @Binding var selectedImage: Int?
    var ns: Namespace.ID
    
    init(selectedImage: Binding<Int?>, ns: Namespace.ID) {
        self._selectedImage = selectedImage
        self.ns = ns
        // initialize selctedTab to selectedImage
        self._selectedTab = State(initialValue: selectedImage.wrappedValue ?? 0)
    }
    
    @State private var selectedTab: Int
    
    var body: some View {
        TabView(selection: $selectedTab) {
            
            ForEach(wallpaperSet.indices) { index in
                
                Image(wallpaperSet[index].name)
                    .resizable()
                    .tag(index) // << the images in TabView need tags to identify
                    .ignoresSafeArea()

                    .matchedGeometryEffect(id: index == selectedTab ? selectedTab : 0,
                                           in: ns, isSource: true)
                                
                    .onTapGesture {
                        withAnimation {
                            selectedImage = nil
                        }
                    }
            }
        }
        .ignoresSafeArea()
        .tabViewStyle(.page(indexDisplayMode: .never) )
    }
}