I'm trying to recreate the Tag people functionality in Instagram. Where a carousel of media the user has selected is displayed to them. They can then go through and tag people to the media.
I'm trying to achieve this (but with food items instead of people) with TagView using PHAssets however the result is some funky behaviour I'm pulling my hair out trying to understand.
The items are tagging correctly but the scroll feature on the TabView works sporadically. It occasionally scrolls fine but all of a sudden won't let me scroll past one image.. (See attached video for example).
import SwiftUI import Photos
struct TagItemView: View { @Binding var selectedAssets: [PHAsset] @State private var showTagSheet = false @State private var currentAsset: PHAsset? { didSet { if let currentAsset = currentAsset { assetTags = tags[currentAsset.localIdentifier] ?? [] } } } @State private var tags: [String: [String]] = [:] // Dictionary to store tags for each media item @State private var assetTags: [String] = [] // Tags for the current asset
var body: some View {
VStack {
mediaCarousel
tagsView
Spacer()
}
.background(Color.black.ignoresSafeArea())
.onAppear {
if let firstAsset = selectedAssets.first {
currentAsset = firstAsset
}
}
.onChange(of: currentAsset) { newAsset in
if let currentAsset = newAsset {
assetTags = tags[currentAsset.localIdentifier] ?? []
print("currentAsset changed: \(currentAsset.localIdentifier)")
print("assetTags: \(assetTags)")
}
}
.sheet(isPresented: $showTagSheet) {
TagSheetView(selectedAsset: $currentAsset, tags: $tags, showTagSheet: $showTagSheet, assetTags: $assetTags)
}
}
private var mediaCarousel: some View {
VStack {
TabView(selection: $currentAsset) {
ForEach(selectedAssets, id: \.self) { asset in
if asset.mediaType == .image {
TagItemImageView(asset: asset)
.tag(asset.localIdentifier)
.onAppear {
currentAsset = asset
print("Asset in view (onAppear): \(asset.localIdentifier)")
}
.onTapGesture {
currentAsset = asset
showTagSheet = true
}
} else if asset.mediaType == .video {
TagItemVideoView(asset: asset)
.tag(asset.localIdentifier)
.onAppear {
currentAsset = asset
print("Asset in view (onAppear): \(asset.localIdentifier)")
}
.onTapGesture {
currentAsset = asset
showTagSheet = true
}
}
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.frame(height: UIScreen.main.bounds.height * 0.4) // Fixed height for carousel
}
}
private var tagsView: some View {
ScrollView {
if !assetTags.isEmpty {
ItemView(assetTags: assetTags, removeTag: { tag in
removeTag(tag, from: currentAsset!)
})
.transition(.opacity)
} else {
InstructionsView()
.transition(.opacity)
}
}
.background(Color.black)
.padding(.top, 8)
.padding(.horizontal, 15)
}
private func removeTag(_ tag: String, from asset: PHAsset) {
guard var assetTags = tags[asset.localIdentifier] else { return }
assetTags.removeAll { $0 == tag }
tags[asset.localIdentifier] = assetTags
if currentAsset?.localIdentifier == asset.localIdentifier {
self.assetTags = assetTags
}
}
}