我正在学习SwiftUI,并试图使用LazyVGrid实现一个照片库应用程序。
在ContentView的body()方法的ForEach循环中,我有一个从库中提取的每张照片的缩略图视图。
import SwiftUI
import Photos
import CoreImage
import ImageIO
import AVKit
import AVFoundation
struct Content: Identifiable {
let id = UUID()
let phAsset: PHAsset
let index: Int
}
struct ContentView: View {
@State private var contents: [Content] = []
@State private var selectedContent: Content? = nil
@State private var isLoading: Bool = true
var body: some View {
NavigationView {
let minItemWidth: CGFloat = 100
let spacing: CGFloat = 2
let screenWidth = UIScreen.main.bounds.width
let columns = Int((screenWidth + spacing) / (minItemWidth + spacing))
let totalSpacing = spacing * CGFloat(columns - 1)
let itemWidth = (screenWidth - totalSpacing) / CGFloat(columns)
ZStack {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))], spacing: 2) {
ForEach(contents) { content in
ThumbnailView(content: content.phAsset)
.frame(width: itemWidth, height: itemWidth)
.onTapGesture {
selectedContent = content
}
.padding(4)
.background(Color.blue.opacity(0.5))
.clipped()
}
}
.padding(2)
}
.navigationTitle("Photos Library")
.onAppear(perform: loadContents)
.sheet(item: $selectedContent) { content in
NavigationView {
DetailImageView(asset: content.phAsset)
.navigationBarItems(trailing: Button("Done") {
selectedContent = nil
})
}
}
if isLoading {
ProgressView("Loading...")
.progressViewStyle(CircularProgressViewStyle())
.scaleEffect(1.5, anchor: .center)
}
}
}
}
func loadContents() {
PHPhotoLibrary.requestAuthorization { status in
if status == .authorized {
fetchContents()
}
}
}
func fetchContents() {
let fetchOptions = PHFetchOptions()
DispatchQueue.global(qos: .background).async {
self.isLoading = true
let fetchResult = PHAsset.fetchAssets(with: fetchOptions)
var fetchedContents: [Content] = []
var index = 0
fetchResult.enumerateObjects { (phAsset, _, _) in
fetchedContents.append(Content(phAsset: phAsset, index: index))
index += 1
}
self.isLoading = false
DispatchQueue.main.async {
contents = fetchedContents
}
}
}
}
struct ThumbnailView: View {
let content: PHAsset
@State private var image: UIImage? = nil
var body: some View {
Group {
if let image = image {
Image(uiImage: image)
.resizable()
.scaledToFill()
} else {
Color.gray
}
}
.onAppear(perform: loadImage)
}
func loadImage() {
let imageManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = false
imageManager.requestImage(for: content, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: requestOptions) { (image, _) in
self.image = image
}
}
}
struct DetailImageView: View {
let asset: PHAsset
@State private var image: UIImage?
var body: some View {
Group {
if let image = image {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.all)
} else {
ProgressView()
}
}
.onAppear(perform: loadFullImage)
}
func loadFullImage() {
let manager = PHImageManager.default()
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true
manager.requestImage(
for: asset,
targetSize: PHImageManagerMaximumSize,
contentMode: .aspectFit,
options: options
) { result, _ in
image = result
}
}
}
问题是,当我点击某个项目的某个区域时,打开的项目不是预期的。我试着调试这个问题一整天,发现如果我在ThumbnailView上注释掉“.clipped()”修饰符,我可以看到LazyVGrid的项目视图是重叠的,这就是为什么打开顶部视图而不是我以为我点击的视图的原因。这对我来说很奇怪,因为我相信如果我用.frame()修饰符指定视图的大小,它应该无法接收区域外的任何触摸事件。
我是SwiftUI和iOS编程的新手,非常感谢您的帮助。