스크롤할 때 내비게이션바의 색상이 바뀌는 문제 해결

EenSung Kim·2024년 3월 15일
0

iOS 앱개발 공부

목록 보기
9/10

문제 인식

학습 프로젝트를 진행하는 과정에서 내비게이션 바의 배경색이 스크롤을 할 때마다 바뀌는 문제가 있었습니다. 예를 들어서 처음 화면이 딱 구성되었을 때는 내비게이션바의 배경색이 검은색인데, 스크롤을 하기 시작하면 내비게이션바의 배경색이 회색이 되는 식이었죠.

"스크롤할 때와 하지 않을 때 내비게이션 바의 색상이 달라진다고..?"

이런 저런 방법을 찾아보고 시도해보다가, SceneDelegate 에서 window 의 배경색을 .systemBackground 로 변경하여 문제를 해결할 수 있었습니다.

window?.backgroundColor = .systemBackground

문제는 해결되었는데 집으로 돌아가는 길에 갑자기 의문이 들었습니다.

"UIKit 에서 뷰는 계층 구조를 가지기 때문에 계층 구조의 가장 아래의 뷰가 제일 위에 노출될 텐데, 왜 윈도우의 배경색을 바꿔준 것이 내비게이션 바의 색상까지 바꿔주는걸까?"


추론 과정

윈도우의 배경색은?

궁금증을 해결하기 위해 우선 window.backgroundColordefault 로 갖는 속성이 무엇일지 공식문서를 찾아가보았습니다.

공식문서를 확인해보니 UIWindowUIView 를 상속받고 있고, backgroundColorUIView 에서 정의하고 있는 속성이더라구요. 그래서 UIViewbackgroundColor 를 확인해 봤더니, 디폴트 값은 nil 이고 배경색은 투명하게 적용된다는 점을 알 수 있었습니다.

"기본값이 별도로 지정되지 않는다면 투명한 배경색을 지님"

시스템이 자체적으로 가지는 설정이 있는걸까?

기본적으로 모든 뷰는 별도로 지정해주지 않는다면 투명한 배경색을 가진다. 이 점을 통해 앞선 의문은 어느 정도 해소가 되었습니다. 뷰의 배경색을 직접 설정해준 적이 없었기 때문에 모든 뷰가 기본적으로는 투명한 상태였고, 그래서 가장 상위의 뷰인 윈도우의 배경색을 지정해준 것이 기본적인 설정 자체를 바꿔준 셈이 된 것이었죠.

추가적인 질문이 떠올랐습니다. 이 추론이 맞다고 가정할 때 들었던 다음 질문입니다.

"시스템이 자체적으로 갖는 어떤 특별한 설정이 있는걸까?"

근데 특별히 어떤 설정의 영향 때문인지는 파악하기가 어려워서 내비게이션 바의 색상이 바뀌는 상황에 관해 구글링을 진행해 봤습니다. 마침 비슷한 질문을 스택오버플로우에서 찾을 수 있었고 해당 글에서 UINavigationBarAppearance 의 존재를 알게 되었습니다.

"UINavigationBarAppearance() 인스턴스를 생성해서 내비게이션바에 전달한다?"

나름의 결론

공식문서에 보면 UIKit 에는 Appearance 라는 것이 있고 기본적인 모양에 관한 설정들을 다뤄준다는 것을 알 수 있습니다. 다크모드에 대해 관심을 가지게 되면 검색을 통해 Appearance customization 이라는 문서를 찾게 되는 루트가 아닐까 싶은데요.

이 문서의 하위에 UINavigationBarAppearance 클래스 문서가 있었습니다. 내비게이션바 외에도 툴바, 탭바가 있고, 이 클래스들은 모두 UIBarAppearance 클래스를 상속받았음을 알 수 있는데요. UINavigationBarAppearance 클래스와 상위 클래스인 UIBarAppearance 클래스를 모두 살펴봐도 스택오버플로우에서 적용하고 있는 appearance() 메서드는 발견할 수 없더라구요. 그래서 다시 검색을 해보니 해당 메소드는 UIAppearance 프로토콜을 채택해서 구성하는 타입 메서드였습니다.

문서를 살펴보면 이 타입메서드는 appearance 의 프록시를 돌려준다고 되어있는데요. UIAppearance 프로토콜 문서에서 조금 더 구체적인 활용 예시를 찾아볼 수 있습니다.

There are two ways to customize appearance for objects: for all instances, and for instances contained within an instance of a container class.

객체의 모양을 정의하는 2가지 방법 중, 위 스택오버플로우에서 활용하는 방법은 모든 인스턴스를 대상으로 하는 방법입니다. appearance() 메서드를 통해 적합한 프록시를 가져와 사용하는 것이죠.

저는 이를 통해 UINavigationBar 가 갖는 standardAppearance,scrollEdgeAppearance 프로퍼티에 적합한 값을 지정해주는 것으로 내비게이션바가 변하는 문제를 해결할 수 있었습니다.

// AppDelegate.swift 에서 설정해 준 모습

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
	let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
    return true
}

참고로 scrollEdgeAppearance 는 스크롤 가능한 콘텐츠의 가장자리가 내비게이션 바의 가장자리와 정렬될 때의 모양이라고 합니다. 저의 경우에는 UICollectionView 의 상단 끝 선이 내비게이션 바의 아래 선과 닿을 때였습니다.


Outro

스크롤뷰와 내비게이션바를 함께 활용하는 과정에서 내비게이션바의 배경색상을 특별히 지정해주지 않았는데 배경색이 바뀌는 현상이 있다면 appearance 에 관한 설정을 지정해주는 것으로 문제를 해결할 수 있습니다.

배워나가는 과정에서 작성한 글이다보니 오류가 있을 수도 있어요. 참고를 부탁드리며, 확인된 내용에 오류가 있다면 언제든 댓글 남겨주시면 감사하겠습니다. (_ _)

profile
iOS 개발자로 전직하기 위해 공부 중입니다.

0개의 댓글

관련 채용 정보