Search code examples
swiftuiuuidimage-gallerylazyvgrid

How to connect 50 thumbnails with the corresponding full size wallpapers in a LazyVGrid? (Xcode 13, iOS15)


Using the full, 2960x1440 wallpapers with LazyVGrid is not an option, as it leads to unsatisfactory performance, even on an iPhone 12 Pro.

All assets are stored in the asset catalog. These are the Models:

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

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

let thumbnailSet = (1...50).map { Thumbnail(name: "thumbnail-\($0)") }
let wallpaperSet = (1...50).map { Wallpaper(name: "wallpaper-\($0)") }

The gallery is a simple two column grid:

import SwiftUI

struct GalleryView: View {
    @State private var fullScreen = false
    let columns = [
        GridItem(.flexible(), spacing: 2),
        GridItem(.flexible())]
    
    var body: some View {
        ZStack {                
            // GRID VIEW
            ScrollView(showsIndicators: false) {
                VStack {
                    LazyVGrid(columns: columns, spacing: 2) {
                        ForEach(thumbnailSet.indices) { index in
                            
                            Image(thumbnailSet[index].name)
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .onTapGesture {(fullScreen = true)}
                        }
                    }
                }
            }
            .ignoresSafeArea()
            
            // FULL SCREEN VIEW
            if fullScreen {
                ZStack {
                    
                    // Code to show corresponding wallpaper?
                    
                    // BACK TO GRID VIEW
                    Button(action: {                            
                        (fullScreen = false)                            
                    }) {Image(systemName: "chevron.left")
                            .font(.system(size: 23))
                            .frame(width: 48, height: 44)
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
                }
                .zIndex(1)
            }
        }
    }
}

Is this doable? Ideas?

Thank you!


Solution

  • You can make your fullscreenan optional index and use that to switch and show the respective wallpaper image:

    EDIT: now with animation

    struct GalleryView: View {
        @State private var fullScreen: Int? = nil // make it an optional index
        
        @Namespace var namespace
        
        let columns = [
            GridItem(.flexible(), spacing: 2),
            GridItem(.flexible())]
        
        var body: some View {
            ZStack {
                // GRID VIEW
                ScrollView(showsIndicators: false) {
                    VStack {
                        LazyVGrid(columns: columns, spacing: 2) {
                            ForEach(thumbnailSet.indices) { index in
                                
                                let fullscreenIndex = fullScreen ?? -1
                                if index == fullscreenIndex {
                                    Color.white
                                } else {
                                Image(thumbnailSet[index].name)
                                    .resizable()
                                    .aspectRatio(1, contentMode: .fill)
                                    .clipped()
                                    .matchedGeometryEffect(id: index, in: namespace)
                                
                                    .onTapGesture {
                                        withAnimation {
                                            fullScreen = index  // set index here
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                .ignoresSafeArea()
                // FULL SCREEN VIEW
                if let fullscreenIndex = fullScreen {
                    ZStack {
                        
                        Color.white
                            .ignoresSafeArea()
                        
                        // show image based on set index
                        Image(wallpaperSet[fullscreenIndex].name)
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .matchedGeometryEffect(id: fullscreenIndex, in: namespace)
    
                        // BACK TO GRID VIEW
                        Button(action: {
                            withAnimation {
                                fullScreen = nil
                            }
                        }) {Image(systemName: "chevron.left")
                                .font(.system(size: 23))
                                .frame(width: 48, height: 44)
                        }
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
                    }
                    .zIndex(1)
                }
            }
        }
    }