[Xcode/SwiftUI] Buttonのロングタップで処理を繰り返す (buttonRepeatBehavior)


.buttonRepeatBehavior(.enabled)なるもの、iOS17から使用可能らしい。

* ちなみにこの記事がめでたく300記事目となりました、やったね 🎉

Contents 非表示

実装

import SwiftUI

struct HomeView: View {
    @State private var count = 0
    var body: some View {
        VStack {
            Text("カウント: \(count)")
                .font(.largeTitle)
            Button {
                count += 1
            } label: {
                Text("Increment")
            }
            .buttonRepeatBehavior(.enabled)
        }

    }
}

ロングタップでcount += 1が繰り返しトリガーされるようになります。

おまけ

何かに使えないかと思って、最近友人のパチンコ話を聞いて平均どれくらいであたるのかのシミュレーションに使ってみた。

1/319の確率で当たる機器が今の最高分母らしいのでそれで試してみる、ガンダムユニコーンくんの機種があるそうなのでそちらで想定 🦄

実装

AudioPlayer.swift

音声再生用、mp3形式で好きなものを入れてください

import UIKit
import AVFoundation

final class AudioPlayer {
    var player: AVAudioPlayer?

    func playSound() {
        guard let url = Bundle.main.url(forResource: "unicorn", withExtension: "mp3") else {
            print("Audio file not found")
            return
        }
        do {
            player = try AVAudioPlayer(contentsOf: url)
            player?.play()
        } catch {
            print("Error playing audio: \(error.localizedDescription)")
        }
    }
}

HomeView.swift

ボタン押されるたびに1/319の抽選をして、当たりなら音声を再生する。

ここで.buttonRepeatBehavior(.enabled)が使えそうだったので使ってみる。(まあfor文で回してもいい気がしたが)

そしてListに何回目で当たったのか記録していく。

import SwiftUI
import AVFoundation

struct HomeView: View {
    @State private var tryCount: Int = 0
    @State private var isButtonDisabled = false
    @State private var jackpotHistory: [Int] = []
    private let audioPlayer = AudioPlayer()

    var body: some View {
        VStack(spacing: 24) {
            Text("\(tryCount)/319\(isButtonDisabled ? "🦄" : "")")
                .font(.largeTitle)
                .padding()
            List {
                ForEach(jackpotHistory, id: \.self) { jackpot in
                    Text("\(jackpot)/319")
                }
            }
            Button {
                tryUnicorn()
            } label: {
                Text("UNICORN!!!")
            }
            .frame(width: UIScreen.main.bounds.width / 1.3, height: UIScreen.main.bounds.height / 28, alignment: .center)
            .padding()
            .foregroundColor(.white)
            .background(isButtonDisabled ? .red : .blue)
            .clipShape(RoundedRectangle(cornerRadius: 27))
            .padding()
            .disabled(isButtonDisabled)
            .buttonRepeatBehavior(.enabled)
        }
    }

    private func tryUnicorn() {
        tryCount += 1
        let jackPotNumber = Int.random(in: 1...319)
        if jackPotNumber == 13 {
            isButtonDisabled = true
            audioPlayer.playSound()
            jackpotHistory.append(tryCount)
            DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                tryCount = 0
                isButtonDisabled = false
            }
        }
    }
}

10回やってみた結果。

分母内で当たる確率は約60%だそうなので試行回数は少ないですがその辺りに落ち着いてそうですね。