Сброс DispatchQueue каждый раз, когда происходит касание - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть простое приложение, которое предназначено для работы следующим образом:

  • Приложение загружается с изображением по умолчанию
  • После получения крана случайное изображение загружается из списка
  • Если в течение 5 секунд не будет получено касание, мы вернемся к изображению по умолчанию

Я пытаюсь выполнить sh, используя DispatchQueue и DispatchWorkItem. Мне удалось заставить работать вышеуказанную функциональность - , за исключением случаев, когда пользователь нажимает несколько раз .

Я предполагаю, что это потому, что мы запускаем DispatchWorkItem с возвратом в исходное состояние каждый раз, когда мы нажимаем без сброса 5 секунд.

Как сбросить изображение обратно к изображению по умолчанию, если в течение 5 секунд не было получено касание при сбросе DispatchQueue?

Здесь это то, что я имею до сих пор:

import SwiftUI



struct PlayView : View {
@ObservedObject var viewRouter: ViewRouter
@State var imageName : String = "smiley"

var body: some View {

    ZStack {
        Color.black
        .edgesIgnoringSafeArea(.all)

        Image(imageName)
    }

    .gesture(
        TapGesture()
            .onEnded {
                let resetToOff = DispatchWorkItem {
                    self.imageName = "smiley"
                }

                self.changeImage()

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5), execute: resetToOff)
            }
    )
    // Activate the options menu
    .onLongPressGesture(minimumDuration: 3) {
            self.viewRouter.currentPage = "menuView"
    }
 }

 func changeImage() {
    let tempImageName : String = self.imageName

        let list : Array = [
            "smileyPink",
            "smileyGreen",
            "smileyRed",
            "smileyBlue",
            "smileyYellow"
        ]

        self.imageName = list.randomElement() ?? ""
 // Ensure that new image selection is not the same as previous image
        while tempImageName == self.imageName {
            self.imageName = list.randomElement() ?? ""
            }
    }
 }

    struct PlayView_Previews : PreviewProvider {
    static var previews: some View {
        PlayView(viewRouter: ViewRouter())
    }
}

Любая помощь с этим будет высоко ценится.

Ответы [ 2 ]

0 голосов
/ 12 февраля 2020

Я думаю, что действительно легко изменить ваш код, чтобы resetToOff что-то делал, только если прошло 5 или более секунд с last tap:

var lastTapped: DispatchTime
...

.gesture(
    TapGesture()
        .onEnded {
             lastTapped = DispatchTime.now() // remember the time of last tap

и затем:

let resetToOff = DispatchWorkItem {
                if self.lastTapped + .seconds(5) <= DispatchTime.now() { // 5 sec passed from last tap
                    self.imageName = "smiley"
                } // otherwise do nothing
            }

Поскольку установка и изменение lastTapped происходит в главном потоке, он безопасен для потоков. Конечно, это означает, что вы потенциально можете добавить элемент «не нужно работать» в основную очередь, но это, вероятно, будет очень слабым.

0 голосов
/ 12 февраля 2020

Было бы проще использовать Таймер, потому что его легко отменить (invalidate) и снова запустить таймер (Timer.scheduledTimer), если пользователь нажмет до того, как Таймер сработает в конце 5 секунд. .

Например, так работает мое приложение LinkSame. Имеется 10-секундный таймер перемещения. Если пользователь не сделал правильного хода в течение 10 секунд после предыдущего хода, он теряет 10 очков и таймер запускается заново. Если пользователь делает действительный ход в течение 10 секунд после предыдущего хода, пользователь получает оценку в зависимости от того, где мы находимся в таймере, и таймер запускается заново. Это все достигается с помощью таймера.

...