애플사이다의 iOS 개발 일지

[UIImage] withRenderingMode(.alwaysTemplate)은 언제 쓸까? - tintColor가 적용되는 영역만 남길 때 본문

iOS

[UIImage] withRenderingMode(.alwaysTemplate)은 언제 쓸까? - tintColor가 적용되는 영역만 남길 때

Applecider 2022. 12. 31. 20:13

Profile 화면을 구현하다가 컬러가 2개 이상 적용된 이미지를 사용했을 때 

이미지 전체가 tintColor로 뒤덮이는 문제가 발생했다.
(왼쪽처럼 구현하고 싶었는데, 오른쪽처럼 나타남)

 

대부분의 화면에서 이미지를 올릴 때 renderingMode를 .alwaysTemplate으로 설정했는데, 이게 원인이었다.

 

이미지의 renderingMode 3개 종류인 automatic/alwaysOriginal/alwaysTemplate을 정리했다.


결론

2개 종류의 이미지를 일반 화면 및 TabBar에 올리고,

Rendering Mode를 automatic, alwaysOriginal, alwaysTemplate 순으로 지정해봤다.

  • Custom Image : 흰색, 회색 2개 컬러가 사용된 이미지
  • System Image : SF Symbol을 활용

그리고 4개 이미지 모두 tintColor를 yellow로 지정했다.

Redering Mode 지정 (왼쪽부터 automatic, alwaysOriginal, alwaysTemplate 순)

  • 2개 색상이 사용된 Custom 이미지를 먼저 보자.
    • 일반 화면 (TabBar가 아닌 영역) : alwaysTemplate을 적용하면 이미지가 날아간다.
    • TabBar 영역 : automatic, alwaysTemplate을 적용하면 이미지가 날아간다.
    • 즉, 2개 색상이 사용된 이미지는 원본 색상을 적용해야 하므로 alwaysOriginal을 쓰면 된다!
  • SF Symbol을 사용한 System 이미지를 보자.
    • alwaysOriginal이 아닐 때, 의도대로 투명한 사람 부분에 backgroundColor가 나타난다.
    • 즉, 1개 색상이 사용된 이미지 또는 System 이미지에 tintColor를 적용해야 하므로 alwaysTemplate을 쓰면 된다!
  automatic alwaysOriginal alwaysTemplate
일반 화면 - Custom Image 원본 원본 이미지 날아감
일반 화면 - System Image 투명한 영역 투명하게 보임 원본
(투명한 부분도 원본색으로 보임)
투명한 영역 투명하게 보임
Tab Bar - Custom Image 이미지 날아감 원본 이미지 날아감
Tab Bar - System Image 투명한 영역 투명하게 보임 원본
(투명한 부분도 원본색으로 보임)
투명한 영역 투명하게 보임

Rendering Mode

UIImage.RenderingMode 공식문서부터 보자.

rendering mode란 UIKit이 이미지의 색상 정보를 어떻게 활용해서 이미지를 나타낼지 제어한다.

  • automatic : default
  • alwaysOriginal : 항상 원본 이미지를 나타낸다. (원본의 색상 정보대로 그린다는 뜻)
  • alwaysTemplate : 원본 색상 정보를 무시하고, *template 이미지를 나타낸다. (tintColor가 적용되는 부분만 남긴다는 뜻)❗️

template 이미지는 Article - Providing images for different appearances에서 자세히 설명한다.
내용 중 tintable images를 간단히 보자.

 

말로 설명하면 어려운데 그림으로 보면 쉽다.

이미지 중 투명한 영역은 backgroundColor가 보인다.

이미지 중 100% opaque 영역에는 tintColor가 100% 적용되고, 25% opaque 영역에는 tintColor가 25% 적용된다.

 

즉, tintColor는 이미지 중 투명한 영역이 아닌 부분에 적용된다.
그래서 tintColor가 적용되는 영역을 본 뜬 것 (색상만 바꾸면 되는 틀 역할)을 template image라고 부른다.

tintColor 맨날 썼는데 이번에 처음 알았음..

이왕 찾아본 김에 tintColor 공식문서도 확인해보자.

  • tintColor는 view hierarchy에 있는 (== UIImageView 위에 올린 모든 view에 적용됨)
    template images를 tint하는 색깔이다.
  • 위에서 다 정리했던 내용이라서 이해하기가 쉬웠다.
  • 즉, template images에 적용되므로 Rendering mode를 .alwaysTemplate으로 설정해야 한다!

예제 코드

예제 코드로 화면에 나타난 이미지를 확인하며 마무리해보자.
전체 코드는 GitHub Repo를 참고

private func makeLayout() {
    // 1️⃣ ImageView (custom)
    // ✅ 주의 - withRenderingMode()는 속성을 바꾼 새로운 image를 반환함 
    let returnedCustomImage = UIImage(named: "custom_profile_fill")?.withRenderingMode(.alwaysOriginal)
//  let customImage = UIImage(named: "custom_profile_fill")
//  let returnedCustomImage = customImage?.withRenderingMode(.automatic)       // 1
//  let returnedCustomImage = customImage?.withRenderingMode(.alwaysOriginal)  // 2
//  let returnedCustomImage = customImage?.withRenderingMode(.alwaysTemplate)  // 3
    customImageView.image = returnedCustomImage
    customImageView.tintColor = .customYellow

    // 2️⃣ ImageView (system)
    let sfImage = UIImage(systemName: "person.circle.fill")
//  let returnedSFImage = sfImage?.withRenderingMode(.automatic)       // 1
    let returnedSFImage = sfImage?.withRenderingMode(.alwaysOriginal)  // 2
//  let returnedSFImage = sfImage?.withRenderingMode(.alwaysTemplate)  // 3
    systemImageView.image = returnedSFImage
    systemImageView.tintColor = .customYellow

    // 3️⃣ Tab Bar (custom)
    let customBarItemImage = UIImage(named: "custom_profile_fill")
//  let returnedCustomBarItemImage = customBarItemImage?.withRenderingMode(.automatic)       // 1
    let returnedCustomBarItemImage =  customBarItemImage?.withRenderingMode(.alwaysOriginal) // 2
//  let returnedCustomBarItemImage =  customBarItemImage?.withRenderingMode(.alwaysTemplate) // 3
    customBarItem.image = returnedCustomBarItemImage

    // 4️⃣ Tab Bar (system)
    let systemBarItemImage = UIImage(systemName: "person.circle.fill")
//  let returnedSystemBarItemImage = systemBarItemImage?.withRenderingMode(.automatic)      // 1
    let returnedSystemBarItemImage = systemBarItemImage?.withRenderingMode(.alwaysOriginal) // 2
//  let returnedSystemBarItemImage = systemBarItemImage?.withRenderingMode(.alwaysTemplate) // 3
    systemBarItem.image = returnedSystemBarItemImage

    mainTabBar.tintColor = .customYellow
    mainTabBar.barTintColor = .customGreen
}

1. automatic

default값이다.

  • Custom 이미지 : 일반 화면에서는 잘 보이지만, Tab Bar 영역에 올린 이미지는 날아간다.
  • System 이미지 : 일반/Tab Bar에서 모두 tintColor가 잘 적용된다.

2. alwaysOriginal

  • Custom 이미지 : 원본 이미지의 색상을 사용하므로 tintColor가 적용되지 않는다.
  • System 이미지 : 사람 부분에 원본 이미지 (흰색)이 적용되고, 나머지 부분에만 tintColor가 적용된다.

🤔 이상하게 System 이미지에는 tintColor가 적용된다?! 

위에서 살펴본대로 alwaysOriginal을 사용하면 원래는 template image를 만들지 않으므로
이미지에 tintColor가 적용되지 않아야 하지만..

SF Symbol을 활용한 system 이미지는 자체 template image가 있어서

tintColor가 나타나는 거라고 예상된다.

3. alwaysTemplate

원본 이미지의 색상을 무시하고, tintColor를 적용할 수 있는 template image를 만든다.

  • Custom 이미지 : 원본 이미지의 색상이 모두 무시되므로 이미지 전체 영역에 tintColor가 적용되어 이미지가 날아간다.
  • System 이미지 : 일반/Tab Bar에서 모두 tintColor가 잘 적용된다.

참고 - Assets에서 Rendering Mode 설정하기

특정 이미지에 대한 Rendering Mode를 직접 설정할 수 있다.

- Reference

 

🍎 포스트가 도움이 되었다면, 공감🤍 / 구독🍹 / 공유🔗 / 댓글✏️ 로 응원해주세요. 감사합니다.

Comments