iOS 응용 (swift)
[iOS - swift] CoreHaptics (진동 주는 방법, 진동 효과)
jake-kim
2024. 10. 9. 01:51
진동 효과 (CoreHaptics)
- 햅틱을 0.5초 주기로 1초 진동을 3번 순차적으로 주고 싶은 경우? -> CoreHaptics를 사용
- 단순히 한 두번의 햅틱 반응을 주고 싶은 경우는 UIImpactFeedbackGenerator, UINotificationFeedbackGenerator 글 참고
- AudioToolbox라는 것을 사용하여 진동 효과를 줄 수 있는데, CoreHaptics가 가장 정교하게 진동 세팅이 가능
- CoreHapcits는 iOS 13부터 제공하며 햅틱의 패턴들을 정교하게 만들어 낼 수 있는 기능
사용 방법
- import
import CoreHaptics
- enum을 사용하여 햅틱의 종류 설정
enum HapticCategory {
case a
case b
}
- a진동은 여러번 주는 진동으로하고, b는 굴직하게 긴 시간 하나의 진동을 주도록 구현
- CHHapticEvent라는 것으로 배열로 반환하는데, 여기서 중요한 파라미터는 eventType, relativeTime, duration 세 가지
- eventType: 대표적으로 duration을 설정할 수 있는 hapticContinous와 단발적으로 진동해시키는 hapticTransient 2개가 존재
- relativeTime: 시작시간 (초) 이며 주의사항은 1초를 기준으로한 상대시간이 아닌 말그대로 시작 초를 의미함
- duration: eventType에서 hapticContinous을 사용했을때 지속시간 (초)
enum HapticCategory {
case a
case b
var hapticEvents: [CHHapticEvent] {
switch self {
case .a:
[
CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.3, duration: 0.5),
CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.9, duration: 0.5),
CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 1.5, duration: 0.5),
]
case .b:
[CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.1, duration: 3)]
}
}
}
- CustomHaptic이라는 클래스 생성
- CHHapticEngine이라는 프로퍼티를 가지고 있게끔 구현
- 이 프로퍼티는 위에서 정의한 hapticEvents들을 가지고 진동효과를 줄 수 있는 API
class CustomHaptic {
private var engine: CHHapticEngine?
}
- 여기에 햅틱을 실행시키는 함수 구현
- resetEngine()이라는 함수는 밑에서 알아볼 예정이며 단순히 engine 프로퍼티를 초기화하고 handler를 등록하는 함수
- guard문으로 햅틱을 지원하는 하드웨어인지 체크 (iOS는 햅틱 지원함)
- CHHapticPattern에 위에서 정의한 hapticEvents들을 넘기고 player로 실행
- 주의할 점) hapticEvents들을 구성할 때 relativeTime이 음수 값이거나 배열에서 relativeTime이 순차적으로 되어 있지 않으면 catch문으로 예외가 발생함
func playHaptic(category: HapticCategory) {
resetEngine() // 밑에서 구현 예정
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
do {
let pattern = try CHHapticPattern(events: category.hapticEvents, parameters: [])
let player = try engine?.makePlayer(with: pattern)
try player?.start(atTime: 0)
} catch {
print("CHHapticEvent 구조가 이상하여 에러 발생 \(error.localizedDescription).")
}
}
- resetEngine() 구현
- engine 초기화 - play할때마다 resetEngine()을 매번 호출하는데, 매번 초기화시켜주지 않으면 간헐적으로 햅틱이 동작 안하는 경우가 존재하기 때문
- 헨들러 등록
private extension CustomHaptic {
func resetEngine() {
engine = try? CHHapticEngine()
try? engine?.start()
setStopHandler()
setResetHandler()
}
func setStopHandler() {
engine?.stoppedHandler = { reason in
print("엔진이 멈춤 \(reason)")
}
}
func setResetHandler() {
engine?.resetHandler = { [weak self] in
do {
try self?.engine?.start()
} catch {
print("restart 실패 \(error)")
}
}
}
}
사용하는쪽)
class ViewController: UIViewController {
let haptic = CustomHaptic()
@objc func didTapButton() {
haptic.playHaptic(category: .a)
}
}
* 전체 코드: https://github.com/JK0369/ExCoreHaptics
* 참고