예거's Bicycle for the mind

[iOS] Scroll Indicator 를 화면의 왼쪽으로 옮기는 방법 (How to move scroll indicator to left side of the scrollView) 본문

iOS & Swift

[iOS] Scroll Indicator 를 화면의 왼쪽으로 옮기는 방법 (How to move scroll indicator to left side of the scrollView)

유예거 2021. 12. 19. 18:53

스크롤 뷰와 스크롤 인디케이터

아마 우리 모두는 하루에도 수백 번씩 스크롤 뷰를 사용할 거라 확신합니다. 😄

마우스의 휠을 통해 드르륵, 드르륵. 또는 손가락을 이용해서 휙휙 화면을 위, 아래로 움직이는데요.

 

우리가 봐야 하는 콘텐츠는 화면의 크기보다 더 길거나 넓을 때, 스크롤 뷰를 활용합니다.

그리고 '스크롤'이라는 행위를 할 때, 사용자에게 스크롤 뷰에서의 사용자가 보고 있는 상대적인 위치를 나타내는 UI 요소가 바로 스크롤 인디케이터(Scroll Indicator)입니다.

 

기본(default) 스크롤 인디케이터의 문제점

<계산기> 프로젝트를 진행하며, 숫자가 쌓이다가 화면을 넘어가면 스크롤 뷰가 활성화되는 기능을 넣었어요.

근데 스크롤 뷰에 기본적으로 탑재되어 있는 default 스크롤 인디케이터가 제가 만든 화면과 어울리지 않더라구요.

 

스크롤 인디케이터가 보이시나요?

저는 검정 바탕에 흰색 글자를 띄운 상황이라, 옅은 색의 스크롤 인디케이터는 시각적으로 거의 보이지가 않는다는 문제점이 있었어요.

또한, 쌓이는 숫자 바로 위에 스크롤 인디케이터를 겹쳐놓는 것도 사용성을 떨어지는 부작용이 있을 거라 생각했습니다.

 

먼저, 스크롤 인디케이터의 색상을 변경해줍시다.

스토리보드에서 스크롤 뷰 클릭하고 Attributes inspector 에서 indicator 의 스타일을 변경해주면 됩니다! 간단하죠?

 

 

스토리보드가 아니라, 코드로 스크롤 인디케이터의 스타일을 바꾸려면 indicatorStyle 프로퍼티에 접근해서 미리 정의된 스타일 열거형으로 지정해주면 됩니다.

 

 

애플이 만들어둔 스크롤 인디케이터 스타일은 3가지(디폴트, 블랙, 화이트)가 있는데요.

저는 검은색 배경에 잘 어울리는 white 인디케이터를 선택하겠습니다.

 

 

어떤가요?

디폴트 스타일보다는 화이트 인디케이터가 훨씬 가시성이 좋다는 걸 확인할 수 있습니다.

하지만 여전히 숫자를 가리고 있다는 문제점이 있죠.

 

스크롤 인디케이터 위치 옮기기

처음엔 간단했어요.

다시 스토리보드에서 스크롤 뷰를 클릭하고, Size inspector 로 넘어가서 indicator insets 를 조정해주면 그냥 끝나는 줄 알았습니다.

 

 

스크롤 뷰의 width 가 382pt 이니까, Right inset 에다 382pt 를 동일하게 부여하면, 스크롤 인디케이터가 왼쪽 화면에 착 달라붙게 될 줄 알았어요.

근데 앱을 다시 실행해보니, 스크롤은 되지만, 인디케이터는 보이지 않더라구요. 🤔

 

 

[Debug View Hierarchy] 기능을 통해 행방불명된 스크롤 인디케이터가 어디 있나 찾아봤는데

스크롤 뷰의 frame 을 벗어나 있더라구요. 그래서 앱에선 보이지 않았습니다.

 

그럼 Right inset 을 스크롤 뷰의 width 와 동일하게 부여하는 게 아니라, 조금 덜 줘야겠죠?

숫자를 얼마나 빼야 할까요?

 

답은 9pt

 

디폴트 상태에서 스크롤 인디케이터는 frame 의 경계선(edge)에 딱 달라붙어 있지 않아요.

자세히 보면 살짝 떨어져 있는 걸 볼 수 있는데, 정확하게 3pt 만큼 떨어져 있습니다.

 

따라서 스크롤 뷰의 width 에서 9pt 만큼을 빼고 Right inset 을 부여해야, 자연스럽게 인디케이터를 화면의 왼쪽에 붙여둘 수 있는 겁니다.

아까 width 가 382pt 였으니까, 이번엔 거기서 9pt 를 뺀 373pt 를 Right inset 에 부여해보겠습니다.

 

 

우리가 처음에 원했던 것처럼, 스크롤 인디케이터가 화면의 왼쪽으로 예쁘게 이동한 걸 확인할 수 있습니다.

이러면 숫자를 가리지도 않고, 검정 백그라운드에 흰색 인디케이터라서 가시성도 좋죠.

 

하지만 여전히 문제점이 있습니다.

바로 스토리보드를 통해서는 고정적인 Right inset 만 지정할 수 있기 때문에

화면 크기가 달라지면, 스크롤 인디케이터가 화면을 다시 빠져나가거나, 아니면 왼쪽 edge 에 착 달라붙어있지 못하게 될 겁니다.

 

 

위 이미지를 보면, 아이폰 13 Pro Max 처럼 큰 화면에서는 넓어진 width 만큼 Right inset 이 조정되지 않아서

스크롤 인디케이터가 왼쪽 edge 에서 조금 떨어진 어색한 모습을 관찰할 수 있습니다.

 

그렇다면 어떻게 반응형으로 대응하게 만들 수 있을까요?

코드를 통해 Right inset 을 넣어주면 됩니다.

 

스크롤 인디케이터를 *모든 아이폰 기기에서* 화면의 왼쪽으로 옮기는 코드

정답 코드 나갑니다.

 

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let scrollViewWidth = calculatorItemsScrollView.frame.width
    calculatorItemsScrollView.verticalScrollIndicatorInsets = UIEdgeInsets(top: .zero,
                                                                           left: .zero,
                                                                           bottom: .zero,
                                                                           right: scrollViewWidth - 9)
    // * 참고) frame.width 와 bounds.width 의 값은 동일하다.
    print(calculatorItemsScrollView.frame.width) // 396
    print(calculatorItemsScrollView.bounds.width) // 396
}

 

주의할 점이 있다면, 제가 스크롤 인디케이터 위치 조정 코드를 viewDidLoad() 안에 넣지 않았다는 점입니다.

 

그 이유는 viewDidLoad() 메서드가 호출되는 시점에서는 아직 오토레이아웃(Constraints)이 적용되지 않았기 때문에, 우리가 스토리보드에서 확인했던 width 가 안 나옵니다. 결국 스크롤 인디케이터가 이상하게 적용돼요.

 

레이아웃 관련 메서드 호출 순서

 

위 레이아웃 관련 메서드 호출 순서를 확인해보세요.

Constraints, Subviews Layout 은 viewDidLoad() 는 물론, viewWillAppear() 메서드가 호출된 이후에서야 적용된다는 걸 알 수 있습니다.

 

따라서, 스크롤 인디케이터의 위치 조정 코드는, 오토레이아웃 조정이 다 끝난 viewDidAppear() 메서드 내부에 넣어둬야 안전하다고 판단했습니다.

 

화면이 나타난 뒤에서야 위치를 조정하는 것이지만, 어차피 스크롤 인디케이터는 앱이 켜지자마자 보이는 게 아니니까요. ㅎㅎ

 

 

위 코드를 적용하고 다양한 아이폰 기기에서 실행해보면

화면이 변하더라도 스크롤 인디케이터는 스크롤 뷰의 왼쪽 edge 에서 딱 3pt 만큼 떨어진 모습으로 예쁘게 자리 잡은 걸 확인할 수 있습니다. 😁

 

참고 링크

[애플 공식 문서] UIScrollView

[아주 작은 개발자의 블로그] iOS의 레이아웃 사이클

 

Comments