while developing my iOS app I encountered a problem with getting image in Array of UIImageViews to perform an action on that specific image. No matter which picture from my LazyVGrid photo collection I do LongPressGesture action on, it always applies to the first picture which is displayed. I think this might be an issue with the ids in my array that ForEach loop do not recognize each element properly, however I have no idea how to solve it.
I keep my array in ProfileViewModel class:
@Published var userPicturesView: [UIImageView] = [UIImageView]()
And I'm looping through it in my ProfileView:
ScrollView() {
LazyVGrid(columns: Array(repeating: GridItem(), count: 3)) {
ForEach(0..<profileViewModel.userPicturesView.count, id: \.self) { imageIndex in
if profileViewModel.userPicturesView[imageIndex].image != nil {
Image(uiImage: profileViewModel.userPicturesView[imageIndex].image!)
.resizable()
.border(Color.black, width: 0.25)
.frame(width: screenWidth * 0.34, height: screenHeight * 0.17)
.onLongPressGesture {
withAnimation {
self.shouldPresentEditActionSheet = true
}
}
.actionSheet(isPresented: $shouldPresentEditActionSheet) {
ActionSheet(title: Text("Edit selected"), message: nil, buttons: [
.default(Text("Set as profile picture"), action: {
withAnimation {
self.profilePictureImage = Image(uiImage: self.profileViewModel.userPicturesView[imageIndex].image!)
}
}),
.destructive(Text("Delete this photo"), action: {
withAnimation {
self.profileViewModel.deleteUserImage(imageIndex: imageIndex)
}
}),
.cancel()
])
}
}
}
}
}
I can add that I tried solving it by adding custom struct that holds my picture:
struct PictureView: Identifiable {
var id = UUID()
var uiImageView: UIImageView
init(uiImageView: UIImageView) {
self.uiImageView = uiImageView
}
}
and then making an array of this structs in ProfileViewModel like this:
@Published var userPicturesView: [PictureView] = [PictureView]()
Then changing ProfileView in this way:
ScrollView() {
LazyVGrid(columns: Array(repeating: GridItem(), count: 3)) {
ForEach(self.profileViewModel.userPicturesView) { userPictureView in
if userPictureView.uiImageView.image != nil {
Image(uiImage: userPictureView.uiImageView.image!)
.resizable()
.border(Color.black, width: 0.25)
.frame(width: screenWidth * 0.34, height: screenHeight * 0.17)
.onLongPressGesture {
withAnimation {
self.shouldPresentEditActionSheet = true
}
}
.actionSheet(isPresented: $shouldPresentEditActionSheet) {
ActionSheet(title: Text("Edit selected"), message: nil, buttons: [
.default(Text("Set as profile picture"), action: {
withAnimation {
self.profilePictureImage = Image(uiImage: userPictureView.uiImageView.image!)
}
}),
.destructive(Text("Delete this photo"), action: {
withAnimation {
// self.profileViewModel.deleteUserImage(imageIndex: imageIndex)
}
}),
.cancel()
])
}
}
}
}
}
But this brought the same result. Every help will be appreciated.
CodePudding user response:
Using actionSheet(item:)
instead of actionSheet(isPresented:)
will give you access to the selected item. In iOS 14 , there are issues with isPresented
rendering a previous value first. Here's a simplified version of your code:
struct ContentView: View {
let pictureViews : [PictureView] = []
@State private var selectedItem : PictureView? = nil
var body: some View {
ForEach(pictureViews) { pictureView in
Image(uiImage: pictureView.uiImageView.image!)
.onLongPressGesture {
selectedItem = pictureView
}
}.actionSheet(item: $selectedItem) { item in
ActionSheet(title: Text("Edit selected"), message: nil, buttons: [
.default(Text("Set as profile picture"), action: {
withAnimation {
//use `item` here
}
}),
.destructive(Text("Delete this photo"), action: {
withAnimation {
//use `item` here
}
}),
.cancel()
])
}
}
}