[Xcode/Swift] HapticFeedbackをSingletonでスマート管理

HapticFeedback実装の目的とかUI/UX観点

  • ユーザーの“操作感”はアプリの印象を左右する
  • Haptic Feedback(触覚フィードバック)を入れるだけで「押した感」が伝わる
  • でも毎回Generator書くのは地味にだるい
  • なので、Singletonで一括管理する HapticFeedback.swiftを作っておく

なぜSingletonなのか

  • パフォーマンス面(prepare()の意味)
  • アプリ全体で状態共有不要 → Singleton向き
  • UI操作は頻繁かつ即応性が求められる → 毎回生成NG
  • SwiftUIと組み合わせても安定動作

実装 (HapticFeedback.swift)

import UIKit

final class HapticFeedback {
    static let shared = HapticFeedback()

    private let impactGenerators: [UIImpactFeedbackGenerator.FeedbackStyle: UIImpactFeedbackGenerator] = [
        .light: UIImpactFeedbackGenerator(style: .light),
        .medium: UIImpactFeedbackGenerator(style: .medium),
        .heavy: UIImpactFeedbackGenerator(style: .heavy),
        .soft: UIImpactFeedbackGenerator(style: .soft),
        .rigid: UIImpactFeedbackGenerator(style: .rigid)
    ]
    private let selectionGenerator = UISelectionFeedbackGenerator()
    private let notificationGenerator = UINotificationFeedbackGenerator()

    private init() {}

    func impact(_ style: UIImpactFeedbackGenerator.FeedbackStyle) {
        guard let generator = impactGenerators[style] else { return }
        generator.prepare()
        generator.impactOccurred()
    }

    func selection() {
        selectionGenerator.prepare()
        selectionGenerator.selectionChanged()
    }

    func notification(_ type: UINotificationFeedbackGenerator.FeedbackType) {
        notificationGenerator.prepare()
        notificationGenerator.notificationOccurred(type)
    }
}

使い方

UIKit

ButtonActionとかにそのまま入れる

HapticFeedback.shared.impact(.medium)
HapticFeedback.shared.notification(.success)

SwiftUI

同じく

Button("タップ") {
    HapticFeedback.shared.selection()
}

View拡張すると、↓みたいに使える。

Button("HAPTIC!") {
   print("Hapticだぜ")
}
.hapticTap(.heavy)

extension View {
    func hapticTap(_ style: UIImpactFeedbackGenerator.FeedbackStyle) -> some View {
        self.onTapGesture {
            HapticFeedback.shared.impact(style)
        }
    }
}