접근성 향상을 위한 iOS 커스텀 슬라이더 구현 방법
안녕하세요, 엔비전스 입니다.
미디어 플레이어에서의 시간, 볼륨 조절과 같이 터치 핸들을 드래그 하여 슬라이더를 조절하는 기능은 VoiceOver 사용자를 위한 접근성 구현이 필수적입니다. VoiceOver 사용자는 값 조절이라는 로터 동작을 이용하여 한 손가락 위 또는 아래 쓸기를 통해 해당 슬라이더의 값을 조절하게 됩니다. UISlider와 같은 표준 컨트롤을 사용한다면 접근성에 대한 추가 구현이 필요하지 않지만 UISlider를 적용하더라도 손가락을 드래그 한 상태로 떼는 동작이 완료되었을 때에만 설정된 값이 적용되게 하거나 혹은 UISlider를 사용하지 않고 UIView, UILabel과 같은 커스텀 요소를 사용해서 슬라이더를 구현하는 경우에는 반드시 VoiceOver 사용자가 값 조절 기능을 사용하여 값을 변경할 수 있도록 접근성 구현을 해 주어야 합니다.
UISlider를 구현했으나 드래그를 멈추고 손가락을 뗐을 때만 값이 변경되게 구현한 경우의 접근성 대응에 대해서는 2020년 널리 세미나를 통해 이미 다룬 적이 있으므로 해당 영상을 참고해 주시기 바랍니다.
오늘 본 문서를 통해 함께 살펴보고자 하는 것은 UISlider가 아닌 커스텀으로 구현된 슬라이더를 적용했을 때 접근성 대응을 어떻게 할 것인가 입니다.
AccessibilityTraits = .slider
VoiceOver에서는 UISlider, UIPickerView, UIDatePicker에 초점이 가면 한 손가락 위 또는 아래 쓸기를 통해 값을 조절할 수 있는 옵션을 제공해 줍니다. 그것은 해당 컨트롤에는 접근성과 관련된 이벤트가 API에 함께 포함되어 있기 때문입니다. 그러나 UILabel과 같은 요소는 아무리 그 안에 드래그와 같은 이벤트가 적용되어 있다 하더라도 VoiceOver 입장에서는 텍스트 요소일 뿐입니다. 따라서 우리는 VoiceOver에게 해당 UILabel은 텍스트가 아니고 값을 조절할 수 있는 슬라이더라는 것을 알려 주어야 합니다. 이때 사용할 수 있는 것이 바로 accessibilityTraits 입니다.
elapsedTime.accessibilityTraits = .adjustable
위와 같이 지정해 주면 해당 레이블은 이제는 VoiceOver에서 더 이상 텍스트 요소가 아니라 값 조절이 가능한 요소가 됩니다.
AccessibilityIncrement, AccessibilityDecrement
그런데 위와 같이 작업했다고 해서 VoiceOver 사용자가 값 조절을 할 수 있는 것은 당연히 아닙니다. 해당 요소는 커스텀 컨트롤이기 때문에 한 손가락 위 또는 아래 쓸기를 했을 때 어떤 동작을 해야 하는지에 대한 이벤트를 지정해 주어야 합니다. 그렇지 않으면 해당 제스처를 해도 수행할 이벤트가 없으므로 VoiceOver는 사용자의 제스처에 대한 아무런 동작도 하지 못합니다. 이것은 마치 웹페이지에서 커스텀 요소에 role=”radio”를 적용했는데 화살표키에 대한 키보드 이벤트를 전혀 정의하지 않은 것과 같은 것입니다.
사용자의 한 손가락 위 또는 아래 쓸기에 대한 이벤트를 정의하려면 accessibilityIncrement, accessibilityDecrement 메소드를 오버라이드 한 다음 해당 제스처를 할 때 어떤 동작을 수행할 것인지에 대한 동작 메소드를 넣어 주면 됩니다.
이 두 메소드는 UIAccessibilityAction 프로토콜 하위의 메소드로서 VoiceOver에서의 여러 접근성 액션 중 하나입니다.
참고로 VoiceOver에서 재정의할 수 있는 접근성 액션에는 한 손가락 이중탭, 슬라이더에서 한 손가락 위 또는 아래 쓸기, 세 손가락 화면 스크롤, 두 손가락 문지르기, 두 손가락 이중탭, 커스텀 액션입니다.
accessibilityIncrement, accessibilityDecrement를 오버라이드 하려면 해당 객체를 커스텀 클래스로 지정해 주어야 합니다. 따라서 앞에서 예로 든 elapsedTime 객체를 스토리보드의 Identity 섹션에서 커스텀 클래스 네임을 지정합니다. 저는 AccessibilitySlider로 커스텀 클래스를 설정하였습니다. 그런 다음 다음 예시와 같이 AccessibilitySlider 클래스를 만듭니다.
class AccessibilitySlider: UILabel {...
다음으로 accessibilityIncrement, accessibilityDecrement 제스처를 했을 때 미디어 재생 구간이 변경되어야 하므로 이에 필요한 변수를 설정한 다음 다음 예시와 같이 이에 대한 메소드를 정의합니다.
...
override func accessibilityIncrement() {
if ((audioPlayer?.isPlaying) != nil) {
audioPlayer?.currentTime = (audioPlayer?.currentTime ?? 0) + deltaValue!
}
}
override func accessibilityDecrement() {
if ((audioPlayer?.isPlaying) != nil) {
audioPlayer?.currentTime = (audioPlayer?.currentTime ?? 0) - deltaValue!
}
}
accessibilityLabel, accessibilityValue
슬라이더로 변경된 객체에는 대체 텍스트와 접근성 밸류 값을 지정해 주어야 합니다. 한 손가락 위 또는 아래 쓸기로 값을 조절하면 VoiceOver는 업데이트 된 접근성 밸류 값을 말하게 됩니다. 따라서 대체 텍스트는 ‘경과 시간’과 같이 고정된 텍스트로 두고 시간이 변경될 때마다 accessibilityValue를 업데이트 시켜주면 됩니다. 단 안드로이드와 달리 accessibilityValue는 사용자가 한 손가락 위 또는 아래 쓸기를 통해 값을 변경할 때만 읽어주며 자동으로 변경될 때는 값을 읽어주지 않습니다.
이러한 커스텀 슬라이더는 다음과 같은 경우에도 사용할 수 있습니다.
좌 또는 우로 스크롤 가능한 콘텐츠: ScrollView 안에 10개가 넘는 콘텐츠가 담겨 있다고 생각해 봅시다. 그리고 해당 ScrollView는 상하가 아닌 좌 또는 우로 스크롤되는 콘텐츠입니다. 비장애인은 사용자의 필요에 따라 좌 또는 스크롤을 해서 콘텐츠를 보거나 혹은 다음 섹션의 콘텐츠로 바로 이동할 수 있습니다. 그러나 VoiceOver 사용자는 사용자의 선택과 상관없이 해당 영역에서 한 손가락 좌 또는 우로 쓸기를 하면 해당 ScrollView 콘텐츠의 끝까지 다 탐색을 해야 합니다. 이 때 ScrollView 하위 콘텐츠는 접근성 초점에서 숨기고 ScrollView 자체에 초점을 제공해준 다음 값 조절 제스처를 통해서 콘텐츠를 탐색할 수 있게 한다면 내비게이션이 훨씬 효율적일 것입니다.
VoiceOver는 상위 컨테이너에 접근성 초점이 제공되면 안드로이드와 달리 하위 컨테이너에는 초점이 제공되지 않습니다. 따라서 ScrollView에 isAccessibilityElement = “true” 속성을 주면 하위 10개가 넘는 각 객체에는 초점 제공이 되지 않습니다. 따라서 ScrollView 자체에 초점을 주고 accessibilityTraits = .adjustable 속성을 준 다음 accessibilityIncrement, accessibilityDecrement 메소드를 오버라이드 하여 화면도 스크롤되고 accessibilityValue 역시 스크롤된 콘텐츠로 변경해 준다면 훨씬 탐색이 용이할 것입니다.
지금까지 커스텀 슬라이더에서의 접근성 적용방법에 대해 살펴보았습니다. 다음에는 AccessibilityElements에 대해 함께 살펴보도록 하겠습니다.