iOS

isAccessibilityElement / accessibilityElements

Zedd0202 2024. 2. 11. 18:04
반응형

 

# isAccessibilityElement

element가 접근성 요소인지 여부를 나타내는 Bool값

 

UIKit control이 아닌경우 기본값은 false

- UIControl을 상속받고 있는 UIButton같은것들 ➡️ 기본값 true

- UIView나 UIImageView같은것들 ➡️ 기본값 false

이런경우 기본적으로 UIButton에만 접근성 요소로 잡힐것이다. 

이때, 바깥의 주황색 View에도 접근성 요소에 포함하려면, 

self.myView.isAccessibilityElement = true
self.myView.accessibilityLabel = "적절한 accessibilityLabel"

isAccessibilityElement 프로퍼티를 true로 만들어주면 된다. 

UIView에 초점이 갔을 때 뭔가를 읽어줘야하므로 적절한 accessibilityLabel도 같이 넣어주자

 

이때 문제가 하나 발생하는데, 

지금처럼 Parent-Child뷰 관계에서 Parent의 isAccessibilityElement를 true로 해버리면 Child뷰는 접근성 계층 구조에 표시되지 않는다.

즉, 이 상태에서 Child의 버튼에 초점이 가지 않는다.

이거 정확한 이유를 알고싶어서 애플 문서를 뒤적거려봤는데, 찾지는 못했음.. 

참고한 포스팅 : https://medium.com/@jchen_77520/accessibility-and-ui-testing-in-ios-3eb0822a17fb 

아마 이 블로그 글대로 하나의 Parent에 여러 Child가 있을 때 여러번 초점이 가는것을 방지하려고 그런 것 같다.

애플 보이스오버 문서에서도 요런 내용도 있으니 참고!

출처 : https://developer.apple.com/documentation/uikit/accessibility_for_uikit/supporting_voiceover_in_your_app

 

 

이때 2가지 해결책이 있다.

1. Parent의 traits을 button으로 지정하고, Parent를 눌렀을 때 버튼을 눌렀을 때와 동일한 액션을 수행하기 (버튼에 굳이 초점이 안가도 되도록) 

2. 버튼에 초점이 그냥 가게 하기


 

 

 

상황에 따라 다르겠지만 우선 2번만 살펴보자.

self.view.accessibilityElements = [self.myView, self.myButton]

accessibilityElements는 접근성 요소들을 담는 배열이라고 보면 된다.

지금 상태는 myButton이 접근성 요소임에도 불구하고 (UIButton이므로 isAccessibilityElement가 기본적으로 true임) 

Parent의 isAccessibilityElement를 true로 만들었기 때문에 초점이 가지 않는 상태인데,

이를 접근성 요소 배열에 추가해주는 것이다. 

그러면 

이렇게 Parent, Child 둘 다 초점이 잡히게 된다.

accessibilityElements를 사용할 때 주의할 점은, 

self.view.accessibilityElements = [self.myView, self.myButton]

넣은 순서대로 초점이 잡힌다는것이다. 

지금 초점 순서는

주황색 Parent View가 잡히고 -> 스와이프 오른쪽 -> Child 버튼 -> 스와이프 왼쪽 -> 주황색 Parent View 

 

만약 버튼을 먼저 넣었다면 

self.view.accessibilityElements = [self.myButton, self.myView]

Child 버튼이 먼저 잡히고 -> 스와이프 오른쪽 -> 주황색 ParentView -> 스와이프 왼쪽 -> Child 버튼

이 순서대로 초점이 잡히게 된다. 

 

# 심화

그렇다면 뷰가 여러개 중첩되어있을 때의 상황으로 테스트 해보자.

 

민트색 뷰 -> 파랑색 뷰 -> 흰색 뷰 -> 버튼

총 4개의 뷰가 있고, 순서대로 first, second, third, fourth다.

 

일단 알 수 있는 사실은

first, second, third -> isAccessibilityElement == false

fourth(ㅋ버튼) -> isAccessibilityElement == true

접근성 로직에 아~~~무것도 안한상태에서 보이스오버를 켜보면 가장 안쪽의 버튼에만 초점이 간다.

 

# 1. 모든 뷰에 초점이 안가게 하고싶음

지금 접근성 요소가 버튼 하나밖에 없기 때문에.. 

self.fourthButton.isAccessibilityElement = false

를 하면 된다.

근데 만약에 버튼이 막 10개 있어;;;

전부 하나씩 

self.fourthButton.isAccessibilityElement = false

이 짓을 해줄 순 없는데, 

이때는 적절한 Parent에

self.firstView.accessibilityElementsHidden = true

accessibilityElementsHidden를 true로 주면,

해당 View 포함 모든 Subview들이 접근성 요소가 아니게 된다. 

self.firstView.isAccessibilityElement = true
self.firstView.accessibilityElementsHidden = true

이렇게 해도 firstView도 접근성 요소가 아님

 

물론 지금은 first, second, third 어디에서 accessibilityElementsHidden를 하든 상관없다. 

자신의 상황에 맞게 적절한 Parent에 accessibilityElementsHidden 값을 주면 된다.

 

# 2. [first, fourth에만 초점이 가게 하고싶음]

가장 최상위 민트색뷰, 가장 안쪽의 버튼에만 초점이 가도록 해보자.

이건 사실 가장 처음에 봤던 예제랑 똑같은거라서.. 쉽게 할 수 있을것이다. 

self.firstView.isAccessibilityElement = true
self.view.accessibilityElements = [self.firstView, self.fourthButton]

 

그런데, 아까부터 

self.firstView.isAccessibilityElement = true
self.view.accessibilityElements = [self.firstView, self.fourthButton]

여기에 의문을 가진 사람도 있을것이다!!

 

isAccessibilityElement는 firstView에 걸어주는데, accessibilityElements는 왜 view에 걸어주지!? 

(사실 self.accessibilityElements = [~~] 도 동일한데 그냥 view로 해줬다..)

self.firstView.isAccessibilityElement = true
self.firstView.accessibilityElements = [self.firstView, self.fourthButton]

이렇게 둘 다 firstView에 세팅해주면 안되는건가? 

isAccessibilityElement는 당연히 해당하는 뷰에 걸어주는게 맞는데, 

accessibilityElements는 그 상위뷰에 걸어줘야 적용이 된다!! (지금은 firstView의 상위뷰인 UIViewController의 view에 걸어준것)

 

# 3. [second, fourth에만 초점이 가게 하고싶음] 

2번 문제와 원리는 똑같다. 

secondView의 isAccessibilityElement를 true로 만들어주고 accessibilityElements를 세팅해주면되는데..

self.secondView.isAccessibilityElement = true

self.view.accessibilityElements = [self.secondView, self.fourthButton] // 가능 
self.firstView.accessibilityElements = [self.secondView, self.fourthButton] // 가능

이때 당연히 secondView.accessibilityElements 를 세팅해주는게 아니라!!!

상위뷰인 firstView나 최상위뷰이인 view에 넣어줘야 원하는대로 초점이 잡히게 된다. 

(바로 위 상위뷰만 된다는 글도 있는 것 같은데, 나는 최상위뷰에 해도 잘 되는 것 같다;;) 


다만 최상위뷰의 accessibilityElements를 세팅해줄때는 주의해야 할 점이 있다. 

self.view.accessibilityElements = [self.firstView, self.fourthButton]

위 코드는 2번문제 - [first, fourth에만 초점이 가게 하고싶음] 에서 사용한 코드인데.. 

이렇게 상위뷰에 넣어줬으니 firstView와 fourthButton에는 초점이 잘 가겠으나 

밑에 다른 접근성 요소가 있다면, 거기에는 초점이 안가게 된다. (위 그림에서 3번에 초점이 안감) 

self.view.accessibilityElements = [self.firstView, self.fourthButton]

왜냐면 최상위 뷰에 2개만 넣어줬기 때문.....

self.view.accessibilityElements = [self.firstView, self.fourthButton, self.myButton]

그래서 이렇게 myButton도 같이 넣어주거나 해야한다. (myButton == 3번 버튼) 

 

3번 문제에서 

self.view.accessibilityElements = [self.secondView, self.fourthButton] // 가능 
self.firstView.accessibilityElements = [self.secondView, self.fourthButton] // 가능

둘 다 가능하다고는 했지만, view에 넣어준것은 바로 위 문제가 발생하고,

firstView에 넣어준것은 아래 주황색뷰 안에있는 버튼에도 초점이 잘 가게 된다. 

나는 그냥 테스트 프로젝트라서 최상위뷰의 accessibilityElements에 넣어줬지만, 이런 일은 최대한 지양해야할 것 같고

따로 View를 하나 더 만들던가 해서 최상위뷰가 아닌 바로 위 상위뷰에 넣어주는게 가장 좋을 것 같다.

아니면 요걸 다른 방식으로 풀 수 있는것인지는 잘 모르겠다!!! 아시는 분은 댓글로 알려주세여 

 

 

반응형