UIImage(SystemName:)
지금까지는 간단하게 UIImage(systemName: "person.3.sequence.fill")
와 같은 방식으로
이미지를 만들어 왔지만, 렌더링 색상과 Configuration
을 적용할 생각을 하지 않았는데요.
오늘은 시스템 이미지를 커스터마이징하여 사용하는 방법에 대해 살펴보겠습니다.
SFSymbols
SFSymbols는 애플에서 기본으로 제공하는 시스템 이미지입니다.
XCode에서는 UIImage(systemName:)을 사용하여 호출할 수 있습니다.
이미지를 선택할 때 SFSymbols 내에 다양한 렌더링 종류와 종류에 따른 색상이 제공됩니다.
렌더링 색상으로는
단색(Monochrome),
계층(HierarchicalColor),
팔레트(PaletteColors),
여러 가지 색상(Multicolor) 이 있습니다.
XCode에서 SymbolConfiguration
을 사용해 렌더링 색상별로 구현하는 방법에 대해 살펴보겠습니다.
단색(Monochrome)
class func preferringMonochrome() -> Self
이 메서드는 시스템 이미지의 단색 모드를 사용하여 심볼 이미지가 표시되도록 지정하는 색상 구성을 만듭니다.
코드로는 다음과 같이 작성할 수 있습니다.
typealias SFConfig = UIImage.SymbolConfiguration
private let sfImage1 = UIImageView()
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMonochrome()
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage1.tintColor = .systemOrange
applying()
메서드를 통해 SymbolConfiguration들을 추가해줄 수 있습니다.
SymbolConfiguration에 관해서는 뒷부분에서 다뤄보겠습니다.
계층(HierarchicalColor)
코드로는 다음과 같이 작성할 수 있습니다.
typealias SFConfig = UIImage.SymbolConfiguration
private let sfImage1 = UIImageView()
sfImage1.image = UIImage(
systemName: "person.3.sequence.fill",
withConfiguration: SFConfig(hierarchicalColor: .systemRed)
.applying(SFConfig(pointSize: 100, weight: .medium))
)
init(hierarchicalColor: UIColor)
이 메서드는 단일 색상에서 파생된 색상의 계층 조합 구성을 생성합니다.
팔레트(PaletteColors)
코드로는 다음과 같이 작성할 수 있습니다.
typealias SFConfig = UIImage.SymbolConfiguration
private let sfImage1 = UIImageView()
sfImage1.image = UIImage(
systemName: "person.3.sequence.fill",
withConfiguration: SFConfig(paletteColors: [.systemRed, .systemBlue, .systemOrange])
.applying(SFConfig(pointSize: 100, weight: .medium))
)
init(paletteColors: [UIColor])
이 메서드는 여러 가지 색상을 사용하여 색상 조합을 만듭니다.
이를 통해 다양한 색상 표현이 가능해집니다.
여러 가지 색상(Multicolor)
코드로는 다음과 같이 작성할 수 있습니다.
typealias SFConfig = UIImage.SymbolConfiguration
private let sfImage1 = UIImageView()
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMulticolor()
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage1.tintColor = .systemOrange
class func preferringMulticolor() -> Self
이 메서드는 다중 색상을 지원하는 심볼의 경우 심볼 이미지가 다중 색상 구성을 만듭니다.
다중색상은 임의로 설정할 수 없는것 같습니다.
UIImage.SymbolConfiguration
이미지에 Configuration을 적용하는 방법은 2 가지가 있는데요
// withConfiguration
sfImage1.image = UIImage(
systemName: String,
withConfiguration: UIImage.Configuration?
)
// applyingSymbolConfiguration
sfImage1.image = UIImage(systemName: String)?
.applyingSymbolConfiguration(configuration: UIImage.SymbolConfiguration)
이니셜라이저에서 withConfiguration을 사용하여 Configuration을 추가하는 것이
더 깔끔한 코드를 작성할 수 있는 것 같습니다.
1번 방법을 사용해 커스터마이징 하는 방법을 더 설명해 보겠습니다.
Initializer
우선 UIImage.SymbolConfiguration의 이니셜라이저의 종류를 살펴보겠습니다.
Creating a symbol configuration
init(pointSize:)
지정된 포인트 크기 정보를 사용하여 구성 객체를 만듭니다.
init(pointSize: weight)
지정된 포인트 크기와 무게 정보를 사용하여 구성 객체를 만듭니다.
init(pointSize: weight, scale)
지정된 포인트 크기, 무게 및 축척 정보를 사용하여 구성 객체를 만듭니다.
init(scale:)
지정된 축척 정보를 사용하여 구성 객체를 만듭니다.
init(textStyle:)
지정된 글꼴 텍스트 스타일 정보를 사용하여 구성 객체를 만듭니다.
init(textStyle: scale)
지정된 글꼴 텍스트 스타일 및 축척 정보를 사용하여 구성 객체를 만듭니다.
init(weight:)
지정된 무게 정보를 사용하여 구성 객체를 만듭니다.
init(font:)
지정된 글꼴 정보를 사용하여 구성 객체를 만듭니다.
init(font: scale)
지정된 글꼴 및 축척 정보를 사용하여 구성 객체를 만듭니다.
Creating a color configuration
init(hierarchicalColor: UIColor)
한 가지 색상에서 비롯된 색상 구성을 사용하여 색상 구성을 만듭니다.
init(paletteColors: \[UIColor\])
여러 색상으로 이루어진 팔레트에서 색상 구성을 생성합니다.
class func preferringMulticolor() -> Self
심볼 이미지가 다중 색상 변형을 사용하도록 지정하는 색상 구성을 생성합니다.
class func preferringMonochrome() -> Self
심볼 이미지가 단색 변형을 사용하도록 지정하는 색상 구성을 생성합니다.
위 이니셜라이저를 사용해 커스터마이징을 할 수 있는데요
예시코드를 보겠습니다.
PointSize VS Font
pointSize와 FontSize는 같습니다.
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMonochrome()
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage1.tintColor = .systemRed
sfImage2.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(hierarchicalColor: .systemRed)
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage3.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(paletteColors: [.systemRed, .systemBlue, .systemOrange])
.applying(SFConfig(font: .systemFont(ofSize: 100, weight: .medium)))
)
sfImage4.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMulticolor()
.applying(SFConfig(font: .systemFont(ofSize: 100, weight: .medium)))
)
sfImage4.tintColor = .systemRed
Scale
small은 기존 크기 보다 작아집니다.
medium은 기존 크기를 유지합니다.
large는 기존 크기보다 커집니다.
default는 medium과 같습니다.
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMonochrome()
.applying(SFConfig(pointSize: 100, weight: .medium, scale: .small))
)
sfImage2.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(hierarchicalColor: .systemRed)
.applying(SFConfig(pointSize: 100, weight: .medium, scale: .medium))
)
sfImage3.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(paletteColors: [.systemRed, .systemBlue, .systemOrange])
.applying(SFConfig(pointSize: 100, weight: .medium, scale: .large))
)
sfImage4.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMulticolor()
.applying(SFConfig(pointSize: 100, weight: .medium, scale: .default))
)
sfImage4.tintColor = .systemRed
Weight
light → medium → bold → black 순으로 라인이 두꺼워집니다.
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMonochrome()
.applying(SFConfig(pointSize: 100, weight: .light))
)
sfImage2.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(hierarchicalColor: .systemRed)
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage3.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(paletteColors: [.systemRed, .systemBlue, .systemOrange])
.applying(SFConfig(pointSize: 100, weight: .bold))
)
sfImage4.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMulticolor()
.applying(SFConfig(pointSize: 100, weight: .black))
)
sfImage4.tintColor = .systemRed
기존에 정의한 Configure는 다음 Configure가 덮어씁니다
// pointSize가 font를 덮어씌움
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMonochrome()
.applying(SFConfig(font: .systemFont(ofSize: 80, weight: .black)))
.applying(SFConfig(pointSize: 100, weight: .medium))
)
// font가 pointSize를 덮어씌움
sfImage2.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(hierarchicalColor: .systemRed)
.applying(SFConfig(pointSize: 100, weight: .medium))
.applying(SFConfig(font: .systemFont(ofSize: 80, weight: .black)))
)
// tintColor가 paletteColors를 덮어씌움
sfImage3.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig(paletteColors: [.systemRed, .systemBlue, .systemOrange])
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage3.tintColor = .systemPurple
// tintColor가 hierarchicalColor를 덮어씌움
sfImage4.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMulticolor()
.applying(SFConfig(pointSize: 100, weight: .medium))
.applying(SFConfig(hierarchicalColor: .systemPurple))
)
sfImage4.tintColor = .systemRed
코드 개선
위 코드에서 configuration을 만들고 추가하는 과정이 번거롭습니다.
extension을 사용하여 코드를 개선해보았습니다.
Before
sfImage1.image = UIImage(
systemName: "person.crop.circle.badge.plus",
withConfiguration: SFConfig.preferringMonochrome()
.applying(SFConfig(pointSize: 100, weight: .medium))
)
sfImage1.tintColor = .systemRed
After
sfImage1.image = UIImage(systemName: "person.crop.circle.badge.plus")?
.renderingColor(.monochrome)
.pointSize(100)
sfImage1.tintColor(.systemRed)
Configuration을 만드는 과정을 캡슐화하여 메서드 체이닝을 사용하여 쉽게 사용할 수 있습니다.
내구 구현 코드는 아래 깃허브 UIImage+Extension파일에서 확인할 수 있습니다.
VariableValue
iOS 16에서는 아래와 같은 가변 기호를 사용할 수 있습니다.
이미지의 변수 값에 따라 변하는 기호를 만들 수 있는데요
팔레트 구성과 같은 다른 렌더링 모드와 함께 사용할 수도 있습니다.
@objc private func sliderDidValueChange(_ sender: UISlider) {
imageView.image = UIImage(
systemName: "wifi",
variableValue: Double(sender.value),
configuration: UIImage.SymbolConfiguration(paletteColors: [.systemRed])
)
}
오늘은 SF Symbol의 사용법, 코드를 줄이는 방법, 그리고 가변 기호에 대해 알아보았습니다.
UIView 객체를 생성할 때 좀 더 쉽고 직관적인 코드를 작성하는 방법은
아래 깃허브 링크에서 잘 정리되어 있으니 참고하시면 도움이 될 것 같습니다