首页 > 解决方案 > 如何在 SwiftUI 中渲染对象的新实例

问题描述

我有一组图像,并将每个图像渲染为可以拖动的卡片对象。我不想渲染每一个,因为这会导致性能问题。目前我正在使用 forEach 循环来渲染所有这些,但是我将如何渲染说两个,直到一个被删除。一旦一个被删除,我会在当前可见的卡片下渲染一个新实例。我不需要这个确切的实现,但有人可以指出我正确的方法。

import Photos
import SwiftUI

var imageToDelete = [PHAsset]()

struct ContentView: View {
    var body: some View {
        VStack{
            // Here is where I'm rendering the card
            ZStack{
                ForEach(imageObjectGroup){ card in
                    CardView(card: card).padding(8)
                }
            }.zIndex(1.0)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

// You can ignore this I am converting the array item (PHAsset) to a UIImage so I can render it

func getAssetThumbnail(asset: PHAsset) -> UIImage {
    let manager = PHImageManager.default()
    let option = PHImageRequestOptions()
    var thumbnail = UIImage()
    option.isSynchronous = true
    manager.requestImage(for: asset, targetSize: CGSize(width: 350, height: 350), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
        thumbnail = result!
    })
    return thumbnail
}

// Card Object
struct CardView: View{
    @State var card: ImageObject
    let cardGradient = Gradient(colors: [Color.black.opacity(0), Color.black.opacity(0.5)])
    var body: some View{
        ZStack(alignment: .leading){
            Image(uiImage: getAssetThumbnail(asset: card.image)).resizable().padding(8)
            LinearGradient(gradient: cardGradient, startPoint: .top, endPoint: .bottom)
            
            HStack {
                Image("yes").resizable().aspectRatio(contentMode: .fit).frame(width: 150).opacity(Double(card.x/10 - 1))
                Spacer()
                Image("nope").resizable().aspectRatio(contentMode: .fit).frame(width: 150).opacity(Double(card.x/10 * -1 - 1))
            }
        //ZStack follows the coordinates of the card model
        }.offset(x: card.x, y: card.y).rotationEffect(.init(degrees: card.degree)).gesture(
            //Gesture recognizer updates coordinate values
            DragGesture().onChanged { value in
                card.x = value.translation.width
                card.y = value.translation.height
                card.degree = 7 * (value.translation.width > 0 ? 1 : -1)
            }
            //When user stops dragging
            .onEnded { value in
                withAnimation(.interpolatingSpring(mass: 1.0, stiffness: 50, damping: 8, initialVelocity: 0)){
                        switch value.translation.width {
                            case 0...100:
                                card.x = 0; card.degree = 0; card.y = 0
                            // Keep
                            case let x where x > 100:
                                card.x = 200; card.degree = 12
                            case (-100)...(-1):
                                card.x = 0; card.degree = 0; card.y = 0;
                            // Delete
                            case let x where x < -100:
                                card.x = -200; card.degree = -12
                                print(card.image)
                                imageToDelete.append(card.image)
                                PHPhotoLibrary.shared().performChanges( {
                                PHAssetChangeRequest.deleteAssets(imageToDelete as NSFastEnumeration)},
                                completionHandler: {
                                    success, error in NSLog("Deletion prompt complete")
                                })
                            default: card.x = 0; card.y = 0
                        }
                }
            }
        ).cornerRadius(8)
    }
}

标签: swiftxcodeswiftui

解决方案


VStack要渲染里面的每个视图,你需要使用一个惰性视图:

  1. 列表,它是UITableView. 这个的优点是能够使用许多表格视图功能,例如通过滑动删除单元格、重新排序等,但如果您有时不这样做,则很难自定义,例如当您想删除分隔符时等。在苹果列表教程中查看更多信息。我建议你通过所有苹果教程,因为它们非常好
List {
    ForEach(imageObjectGroup){ card in
        CardView(card: card).padding(8)
    }.zIndex(1.0)
}
  1. 第二种方式是LazyVStack包裹在ScrollView. 它的工作方式与VStack加载单元格的方式相同,但以惰性方式加载。在本文中查看更多信息
ScrollView {
    LazyVStack {
        ForEach(imageObjectGroup){ card in
            CardView(card: card).padding(8)
        }.zIndex(1.0)
    }
}

ps 我不知道你为什么用 包装你的卡ZStack,这里是多余的


推荐阅读