SwiftUI .onLongPressGesture() необходимо дважды нажать и удерживать, прежде чем произойдет действие
Я практикую swiftUI, создавая небольшое приложение-альбом камеры, которое обращается к фотоальбому, чтобы пользователь мог выбрать и загрузить фотографию в приложение. Затем отображаются загруженные фотографии, поэтому пользователь выбирает фотографию в качестве основной фотографии. Проблема с.onLongPressGesture()
модификатор, лист действий отображается, когда пользователь долго нажимает на фотографию, чтобы попросить пользователя обновить выбранную или удалить ее. Удаление работает нормально. Однако, если пользователь выбирает «обновить фотографию», то отображается фотоальбом для выбора новой фотографии, а когда фотография выбрана, она не отображается, а старая фотография по-прежнему отображается. Когда та же фотография снова долго нажимается, наконец отображается новая фотография, и снова отображается список действий. Мне нужно, чтобы фотография обновлялась после того, как пользователь выберет новую фотографию.
Пожалуйста, какие-либо предложения по решению этой проблемы? Код показан ниже, спасибо:
class EnvImage: ObservableObject {
@Published var id: UUID
@Published var imagesArray: [UserImages]
init() {
id = UUID()
imagesArray = []
self.objectWillChange.send()
}
}
class UserImages: Identifiable {
let id: UUID
var image: Image
var isSelected: Bool
var isLongPressed: Bool
init(image: Image) {
id = UUID()
self.image = image
isSelected = false
isLongPressed = false
}
}
Использование:
struct ContentView: View {
@StateObject var envImage = EnvImage()
@State private var photo: UIImage = UIImage(systemName: "person.circle")!
@State private var isSelectingPhoto = false
@State private var isShowingActionSheet = false
@State private var isPlusPressed = false
@State private var selectedCardImage: UserImages?
var imageSize: CGFloat = 150
var body: some View {
VStack {
if let selectedCardImage {
selectedCardImage.image
.resizable()
.scaledToFit()
.frame(width: imageSize, height: imageSize)
.cornerRadius(20)
.padding()
} else {
Image(systemName: "person.circle")
.resizable()
.scaledToFit()
.frame(width: imageSize, height: imageSize)
.cornerRadius(20)
.padding()
}
HStack {
ScrollView(.horizontal) {
HStack {
ForEach(envImage.imagesArray, id: \.id) { image in
image.image
.resizable()
.scaledToFit()
.frame(width: imageSize, height: imageSize)
.cornerRadius(20)
.onTapGesture() { // works fine
onTapGesture(image: image) // works fine
}
.onLongPressGesture(minimumDuration: 1) { // issue: must be longe pressed twice to see photo gets updated
onLongGesture(image: image)
}
.padding(10)
}
}
.padding()
}
Spacer()
if envImage.imagesArray.count < 3 {
Button {
isSelectingPhoto = true
isPlusPressed = true
} label: {
Image(systemName: "plus.circle")
.font(.system(size: 40))
}
}
}
}
.sheet(isPresented: $isSelectingPhoto) {
PhotoPicker(vCardImage: $photo)
}
.actionSheet(isPresented: $isShowingActionSheet) {
ActionSheet(title: Text("what would you like to do?"), buttons: [
.default(Text("update photo"), action: {
isSelectingPhoto = true
}),
.destructive(Text("delete photo"), action: {
for (index,image) in envImage.imagesArray.enumerated() where image.isLongPressed == true {
deleteImage(index: index, imageToDelete: image)
}
}),
.cancel()
])
}
.onChange(of: photo) { _ in
if isPlusPressed {
envImage.imagesArray.append(UserImages(image: Image(uiImage: photo)))
isPlusPressed = false
} else {
for image in envImage.imagesArray where image.isLongPressed == true {
if let tempSelectedCard = selectedCardImage, tempSelectedCard.id == image.id {
image.image = Image(uiImage: photo)
selectedCardImage = image
} else {
image.image = Image(uiImage: photo)
}
image.isLongPressed = false
break
}
}
}
.padding()
.preferredColorScheme(.light)
}
func onTapGesture(image: UserImages) {
selectedCardImage = image
image.isSelected = true
for others in envImage.imagesArray where others.id != image.id {
others.isSelected = false
}
}
func onLongGesture(image: UserImages) {
image.isLongPressed = true
for others in envImage.imagesArray where others.id != image.id {
others.isLongPressed = false
}
isShowingActionSheet = true
}
}
func deleteImage(index: Int, imageToDelete: UserImages) {
if let tempSelectedCardImage = selectedCardImage, tempSelectedCardImage.id == imageToDelete.id {
print("same image to delete")
envImage.imagesArray.remove(at: index)
selectedCardImage = nil
} else if let selectedCardImage, selectedCardImage.id != imageToDelete.id {
print("different image to delete, and selectedCardImage not empty")
envImage.imagesArray.remove(at: index)
} else if selectedCardImage == nil {
print("selectedCardImage is empty")
envImage.imagesArray.remove(at: index)
}
}
Спасибо!
Редактировать:
Я редактирую вопрос, потому что нашел временное решение.
The .onLongPressGesture
работает как положено, только если значение.image
назначается@State Image
переменная. В результате я объявил@State private var otherImage = Image(systemName: "person.circle")
, и изменил изображение, используя код внутри блока for-loop.onChange(of: photo)
функционировать, как показано ниже:
.onChange(of: photo) { _ in
if isPlusPressed {
envImage.imagesArray.append(UserImages(image: Image(uiImage: photo)))
isPlusPressed = false
}
else {
for image in envImage.imagesArray where image.isLongPressed == true {
if image.isSelected {
print("image is selected")
image.image = Image(uiImage: photo)
selectedCardImage = image
otherImage = image.image
} else {
image.image = Image(uiImage: photo)
print("other image is selected")
otherImage = image.image
}
break
}
}
}
.padding()
.preferredColorScheme(.light)
Затем, внутриbody
я далotherImage
следующие модификаторы:
otherImage
.resizable()
.scaledToFit()
.frame(width: 1, height: 1)
.hidden()
Это не идеальное решение и не уверен, почему использованиеEnvImage
иUserImages
не работает как положено!! Любые идеи, пожалуйста?