🐙

(SwiftUI)VoiceOverのダイレクト・タッチ領域の実装例

2021/06/13に公開

はじめに

以下の環境で動作検証しました。

  • Xcode Version 12.5 (12E262)
  • iOS 14.5.1

ダイレクト・タッチ領域とは

VoiceOverのジェスチャが完全に無効化される領域をダイレクト・タッチ領域とよびます。

例えば楽器アプリでギターを演奏する場合、指を上下にスワイプすると音が鳴ります。しかし、上下スワイプはVoiceOverのジェスチャと衝突するため、アプリは上下スワイプを認識できません。

この問題を解決するのがダイレクト・タッチ領域です。ダイレクト・タッチ領域を設定するとVoiceOverのジェスチャが完全に無効化されます。

実装例

SwiftUIでダイレクト・タッチ領域を設定するのは簡単です。領域を設定したいViewに対して.accessibilityAddTraits(.allowsDirectInteraction)を追加するだけです。

以下に実装例を示します。画面上の大きな黒い丸をタッチするとタッチした回数が表示されます。

import SwiftUI

struct TouchGestureView: View {
    @State var isPressed = false
    @State var count = 0

    var touch: some Gesture {
        DragGesture(minimumDistance: 0.0, coordinateSpace: .local)
            .onChanged { value in
                if self.isPressed {
                    return
                }

                self.isPressed = true
                self.count += 1
            }
            .onEnded { _ in
                self.isPressed = false
            }
    }
    var body: some View {
        VStack {
            Text("\(self.count)")
                .font(.system(size: 128))
            Circle()
                .fill(self.isPressed ? Color.gray : Color.black)
                .frame(width: 256, height: 256, alignment: .center)
                .gesture(self.touch)
                .accessibilityAddTraits(.allowsDirectInteraction)
        }
    }
}

struct ContentView: View {
    var body: some View {
        TouchGestureView()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

注意点

ダイレクト・タッチ領域内はVoiceOverジェスチャが完全に無効化されます。つまり、画面全体をダイレクト・タッチ領域に設定するとVoiceOverは操作不能になります。当たり判定が必要な箇所だけにダイレクト・タッチ領域を設定してください。

参考資料

  1. AccessibilityTraits | Apple Developer
  2. Direct Touch Interaction Broken in… | Apple Developer Forums
  3. iPhone、iPad、iPod touch の VoiceOver ローターについて - Apple サポート

Discussion