[IOS] UIView의 tintColor 프로퍼티에 대하여
IOS

[IOS] UIView의 tintColor 프로퍼티에 대하여

앱의 화면에서 일관된 글자색과 배경색을 적용하기 위해
tintColor 프로퍼티를 사용하면서 공부하고 경험한 내용을 정리한 글입니다.


1. tintColor의 정의

애플의 개발자 문서에서는 다음과 같이 설명하고 있다.

The first nondefault tint color value in the view’s hierarchy,
ascending from and starting with the view itself.

UIView의 틴트 컬러란 자기 자신의 뷰 객체부터 시작하여 뷰 계층을 따라 올라가면서
처음 만나는 default가 아닌 tintColor의 값을 리턴해주는 프로퍼티이다.

 

tintColor는 시스템 UI가 활성화 상태일때 시각적으로 보여지며,

system 타입의 UIButton에서 흔히 볼 수 있는 SystemBlue 컬러가 기본(default) 틴트 컬러이다.

기본 tintColor 색상

 

2. tintColor의 사용

만약 화면에 있는 모든 시스템 버튼에 대해서 동일한 색을 설정하고 싶다면 각 버튼마다

setTitleColor 메소드를 통해 커스텀 컬러를 지정해야 한다.

 

여기서 tintColor를 사용하면 버튼들을 담고있는 최상위 뷰(예를들어 루트 뷰)의 tintColor를 변경하여
모든 버튼의 색을 일괄적으로 변경할 수 있다.

override func viewDidLoad() {
    super.viewDidLoad()
	
    // 최상위 뷰의 tintColor 변경
    view.tintColor = .systemPink
    
    let button = UIButton(type: .system)
    let tintedButton = UIButton(type: .system)
    let filedButton = UIButton(type: .system)

    view.addSubview(button)
    view.addSubview(tintedButton)
    view.addSubview(filedButton)
}

 

이것이 가능한 이유는 시스템 버튼이 기본 색상으로 tintColor를 사용하기 때문이다.

 

UIButton은 UIView를 상속받기 때문에 tintColor 프로퍼티를 갖고 있으며

이를 이용해 버튼마다 개별적으로 색을 설정할수도 있다.

override func viewDidLoad() {
    super.viewDidLoad()
    view.tintColor = .systemPink
    
    let button = UIButton(type: .system)
    let tintedButton = UIButton(type: .system)
    let filedButton = UIButton(type: .system)
	
    tintedButton.tintColor = .systemOrange
    
    view.addSubview(button)
    view.addSubview(tintedButton)
    view.addSubview(filedButton)
    
}

tintedButton.tintColor = .systemOrange

 

 

스토리보드를 사용한다면 File Inspector에서 Global Tint를 설정할 수 있으며

해당 스토리보드 내부의 모든 화면(뷰 컨트롤러)에 대해 동일한 tintColor를 줄 수 있다.

 

 

유사한 방법으로 UIWindow 객체의 tintColor 값을 변경할 수 있는데

네비게이션 바, 탭 바, 알럿 컨트롤러 등에서 기본 색상으로 tintColor를 사용하는
모든 UI의 색이 변경되는 것을 볼 수 있다.

UIWindow 역시 UIView를 상속받기 때문에 tintColor 프로퍼티가 존재한다.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let scene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: scene)
 
        window?.tintColor = .systemIndigo
        
}

만약 스토리보드와 window 모두 tintColor를 변경했을 경우 뷰 컨트롤러는 스토리보드의 tintColor를 사용한다.

 

3. 이슈

앞서 tintColor는 default 값이 아닌 상위 뷰의 tintColor 프로퍼티 값을 리턴한다고 했다.

따라서 이를 올바르게 사용하려면 tintColor를 사용하는 시점에 뷰의 계층 구조를 고려해야한다.

 

예를 들어, 컬렉션 뷰의 tintColor를 원하는 색으로 설정하고 컬렉션 뷰에서 사용할 셀을
cellForItemAt 메소드에서 커스텀한다고 생각해보자.

 

셀의 배경색을 컬렉션 뷰의 tintColor와 동일하게 만들고 싶어서 아래 처럼 코드를 작성했다.

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
        
        cell.backgroundColor = cell.tintColor
        
        return cell
        
    }


하지만 결과는 셀의 배경색이 변경되지 않는다.

 

그 이유는 tintColor를 사용하는 시점에서

컬렉션 뷰가 컬렉션 뷰 셀을 하위뷰로 갖고 있지 않기 때문이다.

 

스토리보드에서 구성한 뷰 컨트롤러는 viewDidLoad 메소드가 호출됐을때 이미 서브뷰들을 가지고 있지만

cellForItemAt 메소드에서 생성된 컬렉션 뷰 셀의 인스턴스는 아직 서브뷰로 등록되지 않았다.

그래서 이때 셀의 tintColor를 사용하면 컬렉션 뷰의 tintColor를 리턴하지 못하고 기본값이 리턴된다.

따라서 cell의 tintColor 값을 변경해주는 것으로 이슈를 해결할 수 있다.

 

 

4. tintColorDidChanged()

UIView의 tintColor 프로퍼티 값이 변경될때 호출되는 메소드이다.

 

프로퍼티가 변경된 뷰 뿐만 아니라 하위 뷰에서도 호출된다.

 

커스텀 뷰를 만들고 이 메소드를 오버라이드해서 상위 뷰의 tintColor가 바뀔때마다

아래처럼 커스텀뷰를 업데이트 해줄 수 있다.

override func tintColorDidChange() {
    super.tintColorDidChange()

    backgroundColor = tintColor
}

 


틴트 컬러를 처음 사용해봤는데 위에서 언급한 간단하면서도 어려운 이슈를 해결하는데 시간을 많이 쏟았네요.

그래도 덕분에 몰랐던 개념을 확실히 알게 된 것 같습니다.

 

참고자료: https://sarunw.com/posts/tintcolor/

 

tintColor | Sarunw

Introduce you to one of an essential part of iOS theming. What is tintColor and its benefit.

sarunw.com