ButtonStyle を使用してカスタム スタイルのボタンを作成することはできますが、ボタンをタッチして離したときに触覚フィードバックを追加したいと考えています。configuration.isPressed
ButtonStyle で使用できる変数があることは知っていますが、実際に変化したときに触覚フィードバックを与えるにはどうすればよいですか。
触覚フィードバックを提供する方法は知っていますが、ユーザーがいつボタンに触れて開始するかを知るには助けが必要です。
この拡張機能をボタンとして試しました:
struct TouchGestureViewModifier: ViewModifier {
let touchBegan: () -> Void
let touchEnd: (Bool) -> Void
let abort: (Bool) -> Void
@State private var hasBegun = false
@State private var hasEnded = false
@State private var hasAborted = false
private func isTooFar(_ translation: CGSize) -> Bool {
let distance = sqrt(pow(translation.width, 2) + pow(translation.height, 2))
return distance >= 20.0
}
func body(content: Content) -> some View {
content.gesture(DragGesture(minimumDistance: 0)
.onChanged { event in
guard !self.hasEnded else { return }
if self.hasBegun == false {
self.hasBegun = true
self.touchBegan()
} else if self.isTooFar(event.translation) {
self.hasAborted = true
self.abort(true)
}
}
.onEnded { event in
print("ended")
if !self.hasEnded {
if self.isTooFar(event.translation) {
self.hasAborted = true
self.abort(true)
} else {
self.hasEnded = true
self.touchEnd(true)
}
}
self.hasBegun = false
self.hasEnded = false
})
}
}
// add above so we can use it
extension View {
func onTouchGesture(touchBegan: @escaping () -> Void = {},
touchEnd: @escaping (Bool) -> Void = { _ in },
abort: @escaping (Bool) -> Void = { _ in }) -> some View {
modifier(TouchGestureViewModifier(touchBegan: touchBegan, touchEnd: touchEnd, abort: abort))
}
}
次に、ビューでこれを行います。
.onTouchGesture(
// what to do when the touch began
touchBegan: {
// tell the view that the button is being pressed
self.isPressed = true
// play click in sound
playSound(sound: "clickin-1", type: "wav")
// check if haptic feedback is possible
if self.engine != nil {
// if it is - give some haptic feedback
let pattern = try? CHHapticPattern(events: [self.event], parameters: [])
let player = try? self.engine?.makePlayer(with: pattern!)
try? self.engine!.start()
try? player?.start(atTime: 0)
}
},
// what to do when the touch ends. sometimes this doesnt work if you hold it too long :(
touchEnd: { _ in
// tell the view that the user lifted their finger
self.isPressed = false
playSound(sound: "clickout-1", type: "wav")
// check if haptic feedback is possible
if self.engine != nil {
// if it is - give some haptic feedback
let pattern = try? CHHapticPattern(events: [self.event], parameters: [])
let player = try? self.engine?.makePlayer(with: pattern!)
try? self.engine!.start()
try? player?.start(atTime: 0)
}
},
// if the user drags their finger away, abort the action
abort: { _ in
self.isPressed = false
}
)
しかし、途中で動かなくなることがあり、ユーザーにとってはあまり使い物になりません。ButtonStyle を使用したより信頼性の高い Button でそれを行うにはどうすればよいですか?