인터넷 유머에 익숙한 사람, 특히 외국 밈에 익숙한 사람이라면 아래와 같은 형식의 짤을 많이 봤을 것입니다.
대부분의 외국 밈 짤에서는 저렇게 두꺼운 흰색 글자에 검은색 테두리를 갖는 폰트가 사용됩니다.
당장 구글에 'meme'이라고만 검색해도 그 폰트를 잔뜩 볼 수 있습니다.
토이 프로젝트를 하나 만들면서 이 폰트를 사용하고 싶어졌습니다.
해당 프로젝트는 SwiftUI로 진행할 것이기 때문에 SwiftUI로 이 폰트를 사용하는 법을 알아보겠습니다.
그래서 이 폰트가 뭔가요?
외국 밈에서 많이 사용하는 이 폰트의 이름은 'Impact(임팩트)'라고 합니다.
인터넷 밈에 자주 사용되기 때문에 생겨난지 얼마 되지 않은 폰트라고 생각될 수도 있는데, 1965년에 생겨난 매우 근본 있는 폰트라고 합니다.
사진 위에서도 명확하게 텍스트를 구분시켜주는 서체이기 때문에 밈에 자주 쓰이기 시작했다는 것 같습니다.
이 포스팅은 SwiftUI에서 사용하는 법을 다루는 것이 메인이기 때문에, Impact 폰트가 밈에서 많이 쓰이게 된 유래에 대한 설명은 아래 글을 참고해주시면 될 것 같습니다.
https://www.vox.com/2015/7/26/9036993/meme-font-impact
Impact 폰트 다운로드
Impact 서체는 개인 및 상업적 용도로 무료로 사용하는 것이 가능하다고 합니다.
참고로 폰트는 '폰트 서체 자체'가 아니라 '디지털화한 파일 형식인 ttf'일 때 저작권법으로 보호받는다고 하네요. (참고)
SwiftUI에서 커스텀 폰트를 적용하려면 해당 폰트의 ttf 파일을 프로젝트에 추가해야 하기 때문에 다운받아주겠습니다.
저는 여기에서 다운받았습니다.
프로젝트에서 폰트 적용하기
Xcode 프로젝트에 폰트 파일을 추가해 주었습니다.
폰트 파일을 타겟에 추가해주지 않으면 폰트가 적용되지 않기 때문에 Add to targets에 체크를 해줍니다.
그리고 Info.plist에 Fonts provided by application 항목을 추가하여 적용하려는 폰트들을 아이템으로 추가해줍니다.
Text에 폰트를 적용해주는 코드는 아래와 같습니다.
Text("WHY EVERY MEMES USE THIS FONT?")
.foregroundStyle(.white)
.font(.custom("impact", size: 30))
임팩트 폰트가 잘 적용된 것을 볼 수 있습니다.
하지만 뭔가 아쉽습니다.
왜냐하면 텍스트에 검은색 테두리가 빠져 있기 때문이죠
검은색 테두리 적용하기
진짜 밈 서체가 되기 위해 검은색 테두리가 적용된 Text를 만들어보겠습니다.
애플 쪽에서 기본적으로 테두리가 적용된 텍스트를 지원하지는 않기 때문에 직접 테두리를 넣어줘야 합니다.
1. .bold()가 적용된 Text 깔아주기 - ❌
ZStack에서 같은 Text를 2개 겹치고, 더 뒤에 있는 Text에 검은색 서체와 .bold()를 적용해줘봤습니다.
하지만 원하던 모양이 나오지 않았습니다.
Text("WHY EVERY MEMES USE THIS FONT?")
.foregroundStyle(.black)
.font(.custom("impact", size: 30.5))
.bold()
Text("WHY EVERY MEMES USE THIS FONT?")
.foregroundStyle(.white)
.font(.custom("impact", size: 30))
2. 주위로 offset을 적용한 Text 여러개 겹치기 - ✅
위의 방법이랑 비슷하지만 이번에는 bold 텍스트를 깔아주는 것이 아니라, Text의 주변 방향으로 offset만큼 이동시킨 Text들을 여러개 깔아주었습니다. OutlineText라는 이름의 커스텀 Text로 정의해주었습니다.
(여기 코드를 참고하여 만들었습니다.)
struct OutlineText: View {
let text: String
let width: CGFloat
let color: Color
var body: some View {
ZStack{
ZStack{
Text(text).offset(x: width, y: width)
.font(.impactFont30)
Text(text).offset(x: -width, y: -width)
.font(.impactFont30)
Text(text).offset(x: -width, y: width)
.font(.impactFont30)
Text(text).offset(x: width, y: -width)
.font(.impactFont30)
}
.foregroundColor(color)
Text(text)
.font(.impactFont30)
.foregroundStyle(.white)
}
}
}
크기 30에 impact 폰트가 적용된 impactFont30 값을 Font 값의 익스텐션에서 정의해주었습니다.
extension Font {
static let impactFont30: Font = .custom("impact", size: 30)
}
OutlineText를 적용한 모습은 아래와 같습니다.
struct TestView: View {
var body: some View {
ZStack {
Color(.gray)
OutlineText(text: "WHY EVERY MEMES USE THIS FONT?", width: 1, color: .black)
}
}
}
꽤나 괜찮은 것 같습니다.
3. shadow 효과가 적용된 커스텀 modifier 정의하기 - ✅
마지막으로 shadow 효과를 적용해주는 커스텀 modifier를 정의해주는 방법입니다.
(여기 코드를 참고하여 만들었습니다.)
📌 ViewModifier 프로토콜을 채택한 ShadowOutlineModifier를 정의해줍니다.
body(content:) 메서드를 통해 modifier를 호출한 View의 body를 받아와서 원하는 처리가 가능합니다.
아래 modifier에서는 shadow 효과를 인자로 받은 lineWidth 값에 맞게 점점 넓게 적용해줍니다. 이렇게 하면 lineWidth 넓이 만큼 그림자가 지속적으로 진하게 적용됩니다.
📌 View의 익스텐션으로 modifier를 정의해줍니다.
.modifier(ShadowOutlineModifier()) 형식으로 사용할 수도 있지만 편의를 위해 식별하기 쉬운 modifier 명으로 정의해줍니다.
struct ShadowOutlineModifier: ViewModifier {
var color: Color
var lineWidth: Int
func body(content: Content) -> some View {
var newContent = AnyView(content)
for _ in 0..<lineWidth {
newContent = AnyView(newContent.shadow(color: color, radius: 1))
}
return newContent
}
}
extension View {
func shadowOutline(color: Color, lineWidth: Int) -> some View {
self.modifier(ShadowOutlineModifier(color: color, lineWidth: lineWidth))
}
}
modifier를 적용하는 코드입니다.
struct TestView: View {
var body: some View {
ZStack {
Color(.gray)
Text("WHY EVERY MEMES USE THIS FONT?")
.font(.impactFont30)
.foregroundStyle(.white)
.shadowOutline(color: .black, lineWidth: 3)
}
}
}
실제 짤 만들어보기
이제 impact 폰트에 진짜 사진도 같이 활용해서 실제 밈 짤처럼 만들어보겠습니다.
- 2. 커스텀 Text 사용 (offset 적용)
struct TestView: View {
var body: some View {
ZStack {
Image("squirrel")
.resizable()
.aspectRatio(contentMode: .fit)
OutlineText(text: "\n\n\n\n\nI DIDN'T STEAL IT!!!!", width: 2, color: .black)
}
}
}
- 3. 커스텀 modifier 사용 (그림자 효과)
struct TestView: View {
var body: some View {
ZStack {
Image("squirrel")
.resizable()
.aspectRatio(contentMode: .fit)
Text("\n\n\n\n\nI DIDN'T STEAL IT!!!!")
.font(.impactFont30)
.foregroundStyle(.white)
.shadowOutline(color: .black, lineWidth: 5)
}
}
}
그럴싸하네요
참고
https://www.vox.com/2015/7/26/9036993/meme-font-impact
https://www.tosspayments.com/blog/articles/legal2-2
https://cofonts.net/impact-font/
https://stackoverflow.com/questions/57334125/how-to-make-text-stroke-in-swiftui
https://www.youtube.com/watch?v=MJLoKS1i1oQ
'iOS' 카테고리의 다른 글
[iOS] Core Location 테스트하기 (외부 의존성의 응답을 테스트하기) (0) | 2024.05.03 |
---|---|
[iOS] Core Location 사용해보기 (0) | 2024.04.23 |
[iOS] M1 맥북 + Xcode 15 환경에서 SwiftLint 적용 시 오류 처리 (0) | 2024.02.28 |
[ iOS ] CustomStringConvertible 프로토콜 (0) | 2024.02.13 |
[ iOS ] String → URL 변환 시 nil이 반환되는 문제 (0) | 2024.02.12 |