๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

iOS/WWDC

WWDC24) SwiftUI๋กœ ๋งž์ถคํ˜• ์‹œ๊ฐ ํšจ๊ณผ ์ œ์ž‘ํ•˜๊ธฐ

๋ฐ˜์‘ํ˜•

 

[ ์„ธ์…˜ ์†Œ๊ฐœ ]

์ด ์„ธ์…˜์—์„œ๋Š” ๋‹ค์ฑ„๋กญ๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์€ ์•ฑ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‹œ๊ฐ ํšจ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃจ๊ณ  ์žˆ๋‹ค !

์‹œ๊ฐํšจ๊ณผ๋Š” ํŠน์ • ๊ธฐ๋Šฅ์ด ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•จ์„ ๋ณด์—ฌ์ฃผ๊ณ , ์•ฑ ํ™”๋ฉด์— ๊ฐœ์„ฑ์„ ๋”ํ•˜๊ณ , ์ง„ํ–‰์ค‘์ธ ์ค‘์š”ํ•œ ์ผ์— ์ฃผ์˜๋ฅผ ์ง‘์ค‘ ์‹œํ‚ค๋Š” ์—ญํ•  !

์ƒˆ๋กœ์šด ์‹œ๊ฐํšจ๊ณผ๋ฅผ ๋งŒ๋“ ๋‹ค ? ๋นŒ๋“œ๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์—๋Š” ๋ฌด์—‡์ด ์ ํ•ฉํ•œ์ง€ ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ.

 

์„ธ์…˜์—์„œ ๋งŒ๋“ค์–ด๋ณผ ์‹œ๊ฐํšจ๊ณผ๋“ค

- SwiftUI๋กœ ๋งž์ถคํ˜• ์Šคํฌ๋กค ํšจ๊ณผ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

- ๋ฉ”์‹œ ๊ทธ๋ผ๋””์–ธํŠธ๋กœ ์•ฑ์— ํ’๋ถ€ํ•œ ์ƒ‰์ƒ์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

- ๋งž์ถคํ˜• ๋ทฐ ์ „ํ™˜์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

- ํ…์ŠคํŠธ ๋ Œ๋”๋ง์œผ๋กœ ๊ทผ์‚ฌํ•œ ํ…์ŠคํŠธ ์ „ํ™˜์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

- ๊ธˆ์† ์…ฐ์ด๋”๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๊ณ ๊ธ‰ ๊ทธ๋ž˜ํ”ฝ ํšจ๊ณผ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

 

 

โฌ‡๏ธ Scroll effects 

- ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์•ฑ ๊ฒฝํ—˜์€ ์Šคํฌ๋กค ํ•˜๋ฉด์„œ ํ™•์ธํ•˜๋Š” ํ•ญ๋ชฉ์˜ ๋ชจ์Œ. 

๊ฐ€๋กœํ˜• ์Šคํฌ๋กค ๋ณด๊ธฐ ์•ˆ์— ์žˆ๋Š” ์‚ฌ์ง„ ๋ชจ์Œ.

 

- .scrollTargetBehavior(.paging) : ํŽ˜์ด์ง• ๋™์ž‘์„ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€ ๋‚˜๋ˆ„๊ธฐ ํšจ๊ณผ ์ ์šฉ. 

 

- scrollTransitions ์ˆ˜์ •์ž๋Š” ํ‘œ์ค€์ ์ธ ์š”์†Œ ๋ชจ์Œ์„ ๋งž์ถคํ˜• ๋ชจ์Œ์œผ๋กœ ๋ณ€๊ฒฝํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

- scrollTransition์€ ์ „ํ™˜ํ•˜๋ ค๋Š” content์™€ phase๋ฅผ ๋…ธ์ถœ ์‹œํ‚ด

- ์ด๋Ÿฌํ•œ ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํฌ๋กค๋ทฐ์—์„œ ํšŒ์ „์ˆ˜์™€ ์‚ฌ์ง„๋ณ„ offset์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ. ( ์‚ฌ์ง„์˜ ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ )

- ์Šคํฌ๋กค ํ•˜๋ฉด ์–‘์ชฝ์—์„œ ์ด์–ด์ง€๋Š” ์‚ฌ์ง„์ด ํšŒ์ „ํ•˜๋ฉด์„œ ์›ํ˜• ์บ๋Ÿฌ์…€ ํšจ๊ณผ๋ฅผ ๋งŒ๋“ฌ.

- value ์†์„ฑ์„ ํ†ตํ•ด ์ด๋ฏธ์ง€๊ฐ€ ํ™”๋ฉด์—์„œ ๋–จ์–ด์ง„ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฒฐ์ •

- ๋ทฐ๊ฐ€ ํ™”๋ฉด์— ์™„์ „ํžˆ ํ‘œ์‹œ๋˜๋ฉด isIdentity ์†์„ฑ์ด true ๊ฐ€ ๋จ 

 

์ž์„ธํžˆ ์„ค๋ช…ํ•˜์ž๋ฉด,

content: ์‹ค์ œ ๋ณด์—ฌ์งˆ ๋ทฐ (์—ฌ๊ธฐ์„  AnimalPhoto)
phase: ๋ทฐ๊ฐ€ ์Šคํฌ๋กค ์ค‘ ์–ด๋А ์œ„์น˜์— ์žˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ •๋ณด
phase.value: -1.0 ~ 1.0 ๋ฒ”์œ„. ์ค‘์•™์— ๊ฐ€๊นŒ์šธ์ˆ˜๋ก 0
- ์˜ˆ: ์™ผ์ชฝ์— ์žˆ์„ ๋• ์Œ์ˆ˜, ์˜ค๋ฅธ์ชฝ์— ์žˆ์„ ๋• ์–‘์ˆ˜
phase.isIdentity: ๋ทฐ๊ฐ€ ํ˜„์žฌ ์ค‘์‹ฌ(์˜จ์Šคํฌ๋ฆฐ ์ค‘์‹ฌ ์œ„์น˜) ์— ์žˆ์œผ๋ฉด true, ์•„๋‹ˆ๋ฉด false

๐ŸŽจ ํšจ๊ณผ ์„ค๋ช…

๐Ÿ”„ .rotationEffect(.degrees(phase.value * 2.5))
์Šคํฌ๋กค ์ค‘์— ์ด๋ฏธ์ง€๋ฅผ ํšŒ์ „์‹œํ‚ด
phase.value์— ๋”ฐ๋ผ ์ขŒ์šฐ๋กœ ํšŒ์ „
์™ผ์ชฝ์— ์žˆ์„์ˆ˜๋ก ์Œ์ˆ˜ ๊ฐ’ → ์™ผ์ชฝ์œผ๋กœ ํšŒ์ „
์˜ค๋ฅธ์ชฝ์— ์žˆ์„์ˆ˜๋ก ์–‘์ˆ˜ ๊ฐ’ → ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํšŒ์ „

phase.value๊ฐ€ -1.0์ผ ๊ฒฝ์šฐ → -2.5๋„ ํšŒ์ „ (์™ผ์ชฝ์œผ๋กœ)
phase.value๊ฐ€ 0์ผ ๊ฒฝ์šฐ → 0๋„ ํšŒ์ „ (์ค‘์•™)
phase.value๊ฐ€ 1.0์ผ ๊ฒฝ์šฐ → +2.5๋„ ํšŒ์ „ (์˜ค๋ฅธ์ชฝ์œผ๋กœ)

โฌ‡๏ธ .offset(y: phase.isIdentity ? 0 : 8)
์ด๋ฏธ์ง€๊ฐ€ ์ค‘์•™์— ์žˆ์ง€ ์•Š์œผ๋ฉด ์•ฝ๊ฐ„ ์•„๋ž˜๋กœ ์ด๋™
์Šคํฌ๋กค ์ค‘ ์ด๋ฏธ์ง€๊ฐ€ ์˜†์— ์žˆ์„ ๋• y: 8 → ์•„๋ž˜๋กœ 8pt ์ด๋™
์ค‘์‹ฌ์— ์žˆ์œผ๋ฉด y: 0 → ์›๋ž˜ ์œ„์น˜

 

 

 

- modifier๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ scrollTrasition์„ ์—…๋ฐ์ดํŠธ 

- ์ด๋ฏธ์ง€์˜ xOffset์€ ๋ณ€๊ฒฝํ•˜๋˜ ์ด๋ฏธ์ง€๋ฅผ ์ž๋ฅด๋Š” ๋ชจ์–‘์€ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค.

์Šคํฌ๋กค ๊ฐ’์— ๋”ฐ๋ผ ์—…๋ฐ์ดํŠธํ•  ๋ชจ๋“  ์ฝ˜ํ…์ธ ์— ์ด ์ˆ˜์ •์ž๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฏธ์ง€ ์•„๋ž˜์˜ ํ…์ŠคํŠธ ์บก์…˜์— ์Šคํฌ๋กค ์ „ํ™˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋ฏธ์ง€๊ฐ€ ํŽ˜์ด๋“œ ์•„์›ƒ๋˜๊ณ  ์˜คํ”„์…‹ ๋จ

 

์Šคํฌ๋กค ํ•˜๋ฉด์„œ ๋ณผ์ˆ˜ ์žˆ๋Š” ์‹๋ฃŒํ’ˆ ๋ชจ์Œ ๋ชจ๋“  ํ•ญ๋ชฉ์ด ๊ฐ™์€ ์ƒ‰์ƒ์œผ๋กœ ํ‘œ์‹œ๋จ.

 

- visualEffect๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด content ํ”Œ๋ ˆ์ด์Šคํ™€๋”์™€ proxy์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Œ.

- content ํ”Œ๋ ˆ์ด์Šคํ™€๋”์˜ ์ž‘๋™ ๋ฐฉ์‹์€ scrollTransition์—์„œ์™€ ๋™์ผ

- proxy๋Š” ๋ทฐ์˜ ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ ๊ฐ’์„ ์ œ๊ณต

- proxy์˜ ๋ทฐ์˜ ์œ„์น˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ทฐ์˜ ์ƒ‰์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ‹์ง„ ๊ทธ๋ผ๋””์–ธํŠธ ํšจ๊ณผ๊ฐ€ ๋งŒ๋“ค์–ด์ง

- visualEffect๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ทฐ์˜ ์œ„์น˜์™€ ํฌ๊ธฐ์— ๋”ฐ๋ผ ์‹œ๊ฐ์  ์†์„ฑ์„ ํšจ๊ณผ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์Šคํฌ๋กค๋ทฐ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹์Œ.

 

1. .hueRotation(Angle(degrees: ... ))

์ด๊ฑด ์ƒ‰์กฐ(Hue) ๋ฅผ ํšŒ์ „์‹œํ‚ค๋Š” modifier์˜ˆ์š”.
Angle(degrees:) ์•ˆ์— ๋„ฃ๋Š” ์ˆซ์ž๋งŒํผ ์ƒ‰์ƒ ์ŠคํŽ™ํŠธ๋Ÿผ์ด ํšŒ์ „๋ผ์„œ, ๋ณด๋ผ์ƒ‰ → ๋นจ๊ฐ• → ์ฃผํ™ฉ → ๋…ธ๋ž‘ … ์ด๋Ÿฐ ์‹์œผ๋กœ ์ƒ‰์ด ๋ณ€ํ™”ํ•จ
์ฆ‰, ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ๋ทฐ์˜ ์ˆ˜์ง ์œ„์น˜์— ๋”ฐ๋ผ ์ƒ‰์ด ๋‹ฌ๋ผ์ง

2. proxy.frame(in: .global).origin.y

๐Ÿงฑ proxy
.visualEffect { content, proxy in ... } ๊ตฌ๋ฌธ ์•ˆ์˜ proxy๋Š” ํ•ด๋‹น ๋ทฐ์˜ ๋ ˆ์ด์•„์›ƒ ์ •๋ณด๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ์ฒด์˜ˆ์š”.

๐Ÿ“ฆ proxy.frame(in: .global)
์ด๊ฑด ๋ทฐ์˜ ํ”„๋ ˆ์ž„์„ ์–ด๋–ค ์ขŒํ‘œ๊ณ„์—์„œ ๊ณ„์‚ฐํ• ์ง€ ์ง€์ •ํ•˜๋Š” ๊ฑฐ์˜ˆ์š”. .global์„ ์“ฐ๋ฉด → ์Šคํฌ๋ฆฐ ์ „์ฒด ๊ธฐ์ค€์œผ๋กœ ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•จ

๐Ÿ“ .origin.y
์ „์ฒด ์Šคํฌ๋ฆฐ ๊ธฐ์ค€์—์„œ ์ด ๋ทฐ์˜ y์ขŒํ‘œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ ์ฆ‰, ํ˜„์žฌ ๋ทฐ๊ฐ€ ์Šคํฌ๋ฆฐ์˜ ์–ด๋А ์„ธ๋กœ ์œ„์น˜์— ์žˆ๋Š”์ง€๋ฅผ ์˜๋ฏธ

์˜ˆ: ๋งจ ์œ„ ๋ทฐ์˜ origin.y๋Š” 100์ฏค ์•„๋ž˜๋กœ ๊ฐˆ์ˆ˜๋ก origin.y ๊ฐ’์ด ์ปค์ง → ๊ทธ๋ž˜์„œ ์•„๋ž˜์— ์žˆ์„์ˆ˜๋ก ๋” ๋งŽ์ด ์ƒ‰์ด ํšŒ์ „

3. / 10 — ์™œ ๋‚˜๋ˆŒ๊นŒ?

origin.y๋Š” ๋ณดํ†ต ์ˆ˜์‹ญ~์ˆ˜๋ฐฑ pt์ธ๋ฐ, ์ด๊ฑธ ๊ทธ๋ƒฅ ํšŒ์ „ ๊ฐ๋„๋กœ ์“ฐ๋ฉด ์ƒ‰์ด ๋„ˆ๋ฌด ๋นจ๋ฆฌ ๋ฐ”๋€œ
๊ทธ๋ž˜์„œ 10์œผ๋กœ ๋‚˜๋ˆ ์„œ ๋ณ€ํ™” ํญ์„ ์กฐ์ ˆํ•˜๋Š” ๊ฒƒ ์˜ˆ: y=200 → 200 / 10 = 20๋„ ์ƒ‰์ƒ ํšŒ์ „

 

์ƒ‰์ƒ ๋Œ€์‹  ๋‹ค๋ฅธ ์‹œ๊ฐ์  ์†์„ฑ ๋ณ€๊ฒฝ

 

 

- ๋„ํ˜•๊ณผ ๋™์ผํ•œ y์œ„์น˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํฌ๋กค๋ทฐ ์ƒ๋‹จ์—์žˆ๋Š” ์š”์†Œ์— ์˜คํ”„์…‹, ํฌ๊ธฐ์กฐ์ •, ํŽ˜์ด๋“œ ๋ฐ ๋ธ”๋Ÿฌ ํšจ๊ณผ๋ฅผ ์ ์šฉ

 

๊ฒฐ๋ก  : ScrollTransition๊ณผ VisualEffect๋Š” ์ปค์Šคํ…€ ์Šคํฌ๋กค๋ทฐ ํšจ๊ณผ์— ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค 

 

 

- ํ™”๋ฉด์—์„œ ์š”์†Œ์˜ ์œ„์น˜์— ๋”ฐ๋ผ ์Šค์ผ€์ผ์„ ์กฐ์ •ํ•˜๋Š” ์Šคํฌ๋กค๋ทฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ

- ์›๊ทผ๊ฐ์„ ๋ฐ”๊พธ๊ธฐ ์œ„ํ•ด ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Œ ( ํšŒ์ „ ๋ฐ ๊ธฐ์šธ์ด๊ธฐ์™€ ๊ฐ™์€ ๋ณ€ํ˜• ํšจ๊ณผ )

- ์˜คํ”„์…‹์„ ํ†ตํ•ด ์Šคํƒ ๋™์ž‘ ๋งŒ๋“ค๊ธฐ

- ๋ฐ๊ธฐ, ์ฑ„๋„, ์ƒ‰์กฐ์™€ ๊ฐ™์€ ์ƒ‰์ƒ ์†์„ฑ์„ ์กฐ์ •ํ•˜์—ฌ ๋‚ด์šฉ์„ ๊ฐ•์กฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œ์‹œ

 

 

๐ŸŒˆ Color treatments

- ์ƒ‰์ƒ์€ ์ธํ„ฐํŽ˜์ด์Šค์— ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•จ. ์•ฑ์— ๊ฐœ์„ฑ์„ ๋”ํ•˜๊ฑฐ๋‚˜, ์ฃผ์˜๋ฅผ ์ง‘์ค‘์‹œํ‚ค๊ฑฐ๋‚˜ ์˜๋„๋ฅผ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ์Œ.

- SwiftUI๋Š” ์•ฑ์— ์ƒ‰์ƒ์„ ์ ์šฉํ•˜๋Š” ๋„๊ตฌ๋ฅผ ๋‹ค์–‘ํ•˜๊ฒŒ ์ œ๊ณต.

-> ๋‹ค์–‘ํ•œ ๊ทธ๋ผ๋””์–ธํŠธ ์œ ํ˜•, ์ƒ‰์ƒ ์ปจํŠธ๋กค ๋ธ”๋ Œ๋“œ ๋“ฑ์„ ์ง€์›

 

- SwiftUI๋Š” ๋ฉ”์‹œ ๊ทธ๋ผ๋””์–ธํŠธ๋„ ์ง€์›.

- ๋™์  ๋ฐฐ๊ฒฝ์„ ์ ์šฉํ•˜๊ฑฐ๋‚˜ ํ‘œ๋ฉด์— ์‹œ๊ฐ์  ๊ตฌ๋ถ„์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉ

 

- ๋ฉ”์‹œ ๊ทธ๋ผ๋””์–ธํŠธ๋Š” ์ ์˜ ๊ทธ๋ฆฌ๋“œ๋กœ ๋งŒ๋“ค์–ด์ง€๊ณ , ๊ฐ ์ ์€ ์ƒ‰์ƒ๊ณผ ์—ฐ๊ด€๋˜์–ด ์žˆ์Œ

 

- ์ ์„ ์ด๋™ํ•˜๋ฉด ์ƒ‰์ƒํšจ๊ณผ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ. ๋งค๋„๋Ÿฝ๊ฒŒ ๋ธ”๋ Œ๋”ฉ. ๊ฐ€๊นŒ์šด ์ ์€ ์ƒ‰์ƒ์ด ๋” ์„ ๋ช…ํ•˜๊ฒŒ ์ „ํ™˜

 

- width ๋ฐ height ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๋ฆฌ๋“œ์˜ ํ–‰๊ณผ ์—ด์„ ์ •์˜ : 3 x 3 ๊ทธ๋ฆฌ๋“œ

- ๊ทธ๋ฆฌ๋“œ ๋‚ด X ๋ฐ Y ์ขŒํ‘œ์˜ ์œ„์น˜๋ฅผ ์ •์˜ 

- ๊ทธ๋ฆฌ๋“œ ๋‚ด ์ ์€ SIMD2 float ๊ฐ’์œผ๋กœ ์ •์˜๋จ. X ๋ฐ Y ์ถ•์—์„œ 0๋ถ€ํ„ฐ 1๊นŒ์ง€์˜ ๊ฐ’์„ ๊ฐ€์ง

 

SIMD2<Float>๋Š” x, y ์ขŒํ‘œ ํ•œ ์Œ์„ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด

๐Ÿ”น SIMD๋ž€?

SIMD = Single Instruction, Multiple Data → ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ณ ์„ฑ๋Šฅ ๋ฒกํ„ฐ ์—ฐ์‚ฐ ๊ธฐ์ˆ 
Swift์—์„œ๋Š” ์ด๊ฑธ ์œ„ํ•ด SIMD2, SIMD3, SIMD4 ๊ฐ™์€ ํƒ€์ž…์„ ์ œ๊ณตํ•ด์š”.

์˜ˆ : let point = SIMD2<Float>(0.3, 0.7)

 

 - ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ ์ ์— ํ•ด๋‹นํ•˜๋Š” ์ƒ‰์„ ์ถ”๊ฐ€ 

 

๊ฐ€์šด๋ฐ ์ ์˜ ์ขŒํ‘œ๋ฅผ ์˜ฎ๊ธฐ๋ฉด ์ƒˆ ์œ„์น˜์— ๋”ฐ๋ผ ์ƒ‰์ƒ์ด ์ด๋™

 

- ํ‘œ๋ฉด ์ƒ‰์ƒ์„ ์ด๋ฏธ์ง€์— ๋งž์ถฐ ๋ฐ”๊พธ๊ฑฐ๋‚˜ ๋ฉ”์‹œ ๊ทธ๋ผ์ด์–ธํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์Œ์„ ์•Œ๋ฆด ์ˆ˜ ์žˆ์Œ

๐Ÿ“ณ View transitions

- ์‚ฌ์šฉ์ž๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์–ด๋–ค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Œ

- Trasition์€ ์ผ์–ด๋‚˜๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ „๋‹ฌํ•  ๋•Œ ์œ ์šฉ

์˜ˆ) ๋ฒ„ํŠผ์„ ํƒญํ•  ๋•Œ , ์‚ฌ์šฉ์ž๊ฐ€ ์š”์†Œ๋ฅผ ๋“œ๋ž˜๊ทธ

 

- ์•„๋ฐ”ํƒ€๋ทฐ : ์‚ฌ์šฉ์ž์˜ ์˜จ๋ผ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ํ‘œ์‹œ๋˜๊ฑฐ๋‚˜ ์ˆจ๊ฒจ์ง. ์‚ฌ์šฉ์ž๊ฐ€ ์˜จ๋ผ์ธ ์ƒํƒœ๋ฉด ํ‘œ์‹œ๋˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ˆจ๊ฒจ์ง€๋„๋ก

- transition ์ค‘  scale ์ ์šฉ : ์•„๋ฐ”ํƒ€๊ฐ€ ๋“ฑ์žฅํ•˜๊ณ  ์—†์–ด์งˆ ๋•Œ ํฌ๊ธฐ๋ฅผ ๋Š˜๋ฆฌ๊ฑฐ๋‚˜ ์ค„์ž„.

- combined ๋ฉ”์†Œ๋“œ๋กœ ๋‹ค๋ฅธ transition ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

- scale ์ „ํ™˜๊ณผ opacity ์ „ํ™˜ ๊ฐ™์ด ์‚ฌ์šฉ

 

Custom transition 

- ์ปค์Šคํ…€ ํŠธ๋žœ์ง€์…˜์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ƒˆ struct ์ƒ์„ฑ : Twirl

- Transition ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜

- Transition ๋ณธ๋ฌธ ํ•จ์ˆ˜๋Š” content์™€ phase ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉ

- content ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ž‘๋™ ๋ฐฉ์‹์€ ์Šคํฌ๋กค๋ทฐ์—์„œ์˜ ๋ฐฉ์‹๊ณผ ๊ฐ™์Œ : ์ „ํ™˜ํ•  ์ฝ˜ํ…์ธ ์— ๋Œ€ํ•œ ํ”Œ๋ ˆ์ด์Šค ํ™€๋”๋กœ ์ž‘๋™

- phase๊ฐ’์œผ๋กœ ๋ทฐ๊ฐ€ ํ˜„์žฌ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ทฐ์— ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ ์ ์šฉ

 

- scale์˜ ๊ฒฝ์šฐ, ๋ทฐ๋ฅผ ํ‘œ์‹œํ•  ๋•Œ๋Š” ์ตœ๋Œ€ ์Šค์ผ€์ผ๋กœ ํ‘œ์‹œํ•˜๊ณ  ํ‘œ์‹œํ•˜์ง€ ์•Š์„ ๋•Œ๋Š” ์Šค์ผ€์ผ์„ ์ ˆ๋ฐ˜์œผ๋กœ ์ง€์ •

- opacity์˜ ๊ฒฝ์šฐ, ์š”์†Œ๊ฐ€ ์™„์ „ํžˆ ํ‘œ์‹œ๋˜๋Š” ์ƒํƒœ์™€ ์ˆจ๊ฒจ์ง€๋Š” ์ƒ์ฑ„๋ฅผ ์ „ํ™˜ํ•˜๋„๋ก ์„ค์ •

 

์ปค์Šคํ…€ ํŠธ๋žœ์ง€์…˜ ์ ์šฉ

- ๋ธ”๋Ÿฌ ์ถ”๊ฐ€ํ•˜์—ฌ ์•„๋ฐ”ํƒ€๊ฐ€ ์ดˆ์ ์— ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐ€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก, ํšŒ์ „๋„ ์ถ”๊ฐ€ํ•˜์—ฌ ์•„๋ฐ”ํƒ€๊ฐ€ ๋Œ๋„๋ก

- phase ๊ฐ’์„ ํ™•์ธํ•˜๋ฉฐ ๋ณด๊ธฐ๊ฐ€ ํ‘œ์‹œ๋ ์ง€ ๋˜๋Š” ์‚ฌ๋ผ์กŒ๋Š”์ง€ ์•Œ์ˆ˜ ์žˆ์Œ -> ์•„๋ฐ”ํƒ€๊ฐ€ ์‚ฌ๋ผ์งˆ ๋•Œ๋„ ๊ฐ™์€ ๋ฐฉํ–ฅ์œผ๋กœ ํšŒ์ „ํ•˜๋„๋ก ( ์Œ์ˆ˜๊ฐ’ ์‚ฌ์šฉ )

- brightness ์ˆ˜์ •์ž๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ทฐ๊ฐ€ ํ‘œ์‹œ๋ ๋•Œ ์•ฝ๊ฐ„์˜ ๋น›์„ ๋‚ด์–ด ์‹œ์„ ์„ ๋Œ๊ฒŒ 

 

๐Ÿ’ฌ Text transitions

- ํ…์ŠคํŠธ ๋ผ์ธ๋งˆ๋‹ค ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€ 

- TextRenderer : iOS18 ๋ฐ ๊ด€๋ จ ๋ฆด๋ฆฌ์ฆˆ์— ๋„์ž…๋œ ์ƒˆ API

- ๊ฐ•๋ ฅํ•œ ํ”„๋กœํ† ์ฝœ์ธ TextRenderer์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ทฐ ํŠธ๋ฆฌ ์ „์ฒด์—์„œ SwiftUI ํ…์ŠคํŠธ๊ฐ€ ๊ทธ๋ ค์ง€๋Š” ๋ฐฉ์‹์„ ์ปค์Šคํ…€ํ• ์ˆ˜ ์žˆ์Œ

 

- TextRendererํ”„๋กœํ† ์ฝœ์˜ ํ•ต์‹ฌ์€ draw(layout:in:) ๋ฉ”์†Œ๋“œ

- ์ด ๋ฉ”์†Œ๋“œ์˜ ์ธ์ˆ˜๋Š” Text.Layout , GraphicsContext

-  Text.Layout : ํ…์ŠคํŠธ์˜ ๊ฐœ๋ณ„ ๊ตฌ์„ฑ์š”์†Œ์ธ ๋ผ์ธ, ๋Ÿฐ, ๊ธ€๋ฆฌํ”„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ

-  GraphicsContext : ์บ”๋ฒ„์Šค๋ทฐ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Œ. 

- for ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ์˜ ๊ฐœ๋ณ„ ๋ผ์ธ์„ ๋ฐ˜๋ณตํ•˜๊ณ  ์ปจํ…์ŠคํŠธ์— ๊ทธ๋ฆผ => ๊ธฐ๋ณธ ๋ Œ๋”๋ง ๋™์ž‘

-

- ์ „ํ™˜ ์œ ๋„๋ฅผ ์œ„ํ•ด ์†์„ฑ 3๊ฐœ๋ฅผ ์ถ”๊ฐ€

1. elapsedTime : ์ง€๊ธˆ๊นŒ์ง€ ๊ฒฝ๊ณผํ•œ ์‹œ๊ฐ„์„ ์ง€์ •

2. elementDuration : ๊ฐœ๋ณ„ ๋ผ์ธ์ด๋‚˜ ์š”์†Œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ‘œ์‹œํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•  ์‹œ๊ฐ„

3. totalDuration : ์ „์ฒด ์ „ํ™˜์— ์†Œ์š”๋˜๋Š” ์‹œ๊ฐ„

-> SwiftUI๊ฐ€ elapsedTime ๊ฐ’์— ์ž๋™์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Animatable ํ”„๋กœํ† ์ฝœ ๊ตฌํ˜„ 

- animatableData ์†์„ฑ์„ elapsedTime์œผ๋กœ ์ „๋‹ฌํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ์Œ.

 

- ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐ˜๋ณต ์‹œ์ž‘ : ๋ผ์ธ๋ณ„๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ

- ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ „์ฒด์— ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์‹œ๊ฐ„์„ ๊ท ๋“ฑํ•˜๊ฒŒ ๋ถ„๋ฐฐํ•˜๋ ค๋ฉด ์—ฐ์†๋œ ๋‘ ๋ผ์ธ ์‚ฌ์ด์˜ ์ง€์—ฐ ์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•ด์•ผํ•จ.

- ํ—ฌํผ ํ•จ์ˆ˜ ํ˜ธ์ถœ : elementDelay(count:)

- ๋ชจ๋“  ๋ผ์ธ์„ ๋‚˜์—ด : ์ธ๋ฑ์Šค์™€ ํ•ด๋‹น ์ง€์—ฐ ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ƒ๋Œ€์ ์ธ ์‹œ์ž‘ ์‹œ๊ฐ„์„ ๊ณ„์‚ฐ

- ๊ฐœ๋ณ„ ๋ผ์ธ์—์„œ ๊ฒฝ๊ณผํ•œ ์‹œ๊ฐ„์€ ์ „์ฒด ๊ฒฝ๊ณผ ์‹œ๊ฐ„์—์„œ ์š”์†Œ์˜ ๊ฐœ๋ณ„ ์‹œ๊ฐ„ ์˜คํ”„์…‹์„ ๋บ€ ๊ฐ’. 

- ํ˜„์žฌ GraphicsContext์˜ ์‚ฌ๋ณธ์„ ๋งŒ๋“ฌ.

-> GraphicsContext์— ๊ฐ’ ์‹œ๋งจํ‹ฑ์ด ์žˆ์œผ๋ฏ€๋กœ ํ—ฌํผํ•จ์ˆ˜์— ๋Œ€ํ•œ ๊ฐœ๋ณ„ ํ˜ธ์ถœ์ด ์„œ๋กœ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ

- ๋งˆ์ง€๋ง‰์œผ๋กœ ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐœ๋ณ„ ๋ผ์ธ์„ ๊ทธ๋ฆผ

 

๐Ÿง  ์ „์ฒด ํ๋ฆ„ ์š”์•ฝ

Text.Layout ์•ˆ์— ์žˆ๋Š” ํ…์ŠคํŠธ์˜ ๊ฐ ์ค„(line) ์„ ํ•˜๋‚˜์”ฉ ์ˆœํšŒํ•˜๋ฉฐ
๊ฐ ์ค„์— ๋Œ€ํ•ด ์ง€์—ฐ(delay) ์„ ์ฃผ๊ณ  ์ผ์ •ํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜๋˜๋„๋ก
GraphicsContext๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๊ฐ ์ค„์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ทธ๋ฆผ

elementDelay(count:) :์ „์ฒด ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ๊ฐ„์„layout.count (์ค„ ๊ฐœ์ˆ˜) ๋งŒํผ ๊ท ๋“ฑํ•˜๊ฒŒ ๋‚˜๋ˆ”
→ ๊ฐ ์ค„๋งˆ๋‹ค ์‹œ์ž‘ํ•  ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ

layout.enumerated() → ๊ฐ ์ค„๊ณผ ์ธ๋ฑ์Šค๋ฅผ ํ•จ๊ป˜ ์ˆœํšŒ
์˜ˆ: (0, "์ฒซ ๋ฒˆ์งธ ์ค„"), (1, "๋‘ ๋ฒˆ์งธ ์ค„") ...

์ค„ ๋ฒˆํ˜ธ(i) × ์ค„๋‹น ์ง€์—ฐ ์‹œ๊ฐ„(delay) = ์ด ์ค„์˜ ์‹œ์ž‘ ์‹œ๊ฐ„ ์˜คํ”„์…‹
์˜ˆ: 0๋ฒˆ์งธ ์ค„: 0์ดˆ 1๋ฒˆ์งธ ์ค„: 0.2์ดˆ 2๋ฒˆ์งธ ์ค„: 0.4์ดˆ …

ํ˜„์žฌ๊นŒ์ง€ ๊ฒฝ๊ณผํ•œ ์‹œ๊ฐ„ elapsedTime์—์„œ ํ•ด๋‹น ์ค„์˜ ์˜คํ”„์…‹์„ ๋บ€ ๊ฐ’์„ elementTime์œผ๋กœ ์„ค์ •
๋‹จ, ์Œ์ˆ˜๊ฐ€ ๋˜์ง€ ์•Š๊ฒŒ max(0, ...) ํ•˜๊ณ  ์ตœ๋Œ€ ์ง€์†์‹œ๊ฐ„ elementDuration์„ ๋„˜์ง€ ์•Š๊ฒŒ min(..., elementDuration)

โฑ๏ธ ์ฆ‰, ์ด ์ค„์˜ ์ง„ํ–‰๋ฅ ์„ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ!

  • GraphicsContext๋Š” ๊ฐ’ ํƒ€์ž… → ๋ณต์‚ฌํ•ด์„œ ์จ์•ผ ํ•จ
  • ๊ทธ๋ž˜์„œ copy๋ผ๋Š” ์‚ฌ๋ณธ์„ ๋งŒ๋“  ํ›„, ๊ฐ ์ค„ ๊ทธ๋ฆฌ๊ธฐ์šฉ์œผ๋กœ ๊ฐœ๋ณ„ ์‚ฌ์šฉ
  • ์ด ์ค„์—์„œ .draw(...) ํ•จ์ˆ˜๋กœ ์ค„์„ ์‹ค์ œ ๊ทธ๋ฆฌ๋Š” ๋กœ์ง ํ˜ธ์ถœ!


๐Ÿ’ฌ ์™œ context ๋ณต์‚ฌํ•˜๋Š”๊ฐ€?

Swift์˜ GraphicsContext๋Š” ๊ฐ’ ํƒ€์ž…(value semantic)์ด๋ผ์„œ

  • ๊ทธ๋ƒฅ ์‚ฌ์šฉํ•˜๋ฉด ์ด์ „ ์ค„ ๊ทธ๋ฆฐ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Œ
  • ๊ทธ๋ž˜์„œ ๊ฐ ์ค„๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ copy ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ถ€์ž‘์šฉ ์—†์ด ์‚ฌ์šฉ

๋ผ์ธ์„ ๊ทธ๋ฆฌ๊ธฐ ์ „์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•˜๋ ค๋Š” GraphicsContext์˜ ์†์„ฑ์„ ์—…๋ฐ์ดํŠธ

 

๋” ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„์ˆ˜ ์ง„ํ–‰ ๊ฐ’๋„ ๊ณ„์‚ฐ

 

๋ผ์ธ์ด ํŽ˜์ด๋“œ ์ธ๋˜๋„๋ก ๋น ๋ฅธ ๋ถˆํˆฌ๋ช…๋„ ๊ฒฝ์‚ฌ๋ฅผ ๊ณ„์‚ฐ

 

๋™์‹œ์— blurRadius๋ฅผ 0์œผ๋กœ ์ค„์—ฌ ๋ผ์ธ์ด ํ™•์‚ฐ๋œ ์ƒํƒœ์—์„œ ๋‚˜ํƒ€๋‚˜๋Š” ๋А๋‚Œ์„ ์คŒ

 

- ์ฒซ blurRadius๋Š” ๋ผ์ธ์˜ typographicBounds ์†์„ฑ์—์„œ ์ฝ์€ ๋ผ์ธ์˜ ๋†’์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•จ

 

spring์„ ์‚ฌ์šฉํ•˜์—ฌ y์ถ• translation์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉ

 

- ๋ผ์ธ์˜ ๋””์„ผ๋” ๊ธธ์ด์— ๋”ฐ๋ผ ์œ„์ชฝ์œผ๋กœ ์ด๋™ํ•˜๋Š” y์œ„์น˜์—์„œ ์‹œ์ž‘.

 

Baseline : ๊ธ€์ž๊ฐ€ ์ •๋ ฌ๋˜๋Š” ๊ธฐ์ค€์„ 
๋Œ€๋ถ€๋ถ„์˜ ๊ธ€์ž๋Š” ์ด ์„  ์œ„์— ์œ„์น˜
Descender : ๊ธ€์ž์˜ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€๋Š” ๋ถ€๋ถ„
g, y, j, p, q ๋“ฑ์˜ ๊ผฌ๋ฆฌ ๋ถ€๋ถ„

์˜ˆ: g → ๋‘ฅ๊ทผ ์•„๋ž˜ ๊ผฌ๋ฆฌ ๋ถ€๋ถ„ = descender

๋””์„ผ๋”๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์œผ๋ฉด
๊ธ€์ž์˜ ๊ผฌ๋ฆฌ๊ฐ€ ์•„๋ž˜๋กœ ๋–จ์–ด์ ธ์„œ ํ™”๋ฉด ๋ฐ–์œผ๋กœ ์ž˜๋ฆด ์ˆ˜ ์žˆ์Œ

๋””์„ผ๋” ๊ธธ์ด๋งŒํผ ์œ„๋กœ ์˜ฌ๋ฆฌ๋ฉด
ํ…์ŠคํŠธ ์ „์ฒด๊ฐ€ ์ ์ ˆํ•œ ์œ„์น˜์— ๊น”๋”ํ•˜๊ฒŒ ๊ทธ๋ ค์ง

- ๋งˆ์ง€๋ง‰์œผ๋กœ ์ƒˆ draw options ๋ฉ”์†Œ๋“œ๋กœ ๋ผ์ธ์„ ๊ทธ๋ฆผ

- ์„œ๋ธŒ ํ”ฝ์…€ ์–‘์žํ™”๋ฅผ ํ•ด์ œํ•˜๋ฉด spring์„ ์•ˆ์ •ํ™” ์‹œํ‚ค๊ณ  ์ง€ํ„ฐ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Œ.

 โœ… ํ”ฝ์…€ ์–‘์žํ™”(Quantization)

์ขŒํ‘œ๊ฐ’์ด๋‚˜ ๊ทธ๋ž˜ํ”ฝ ์œ„์น˜๋ฅผ ์ •์ˆ˜ ๋‹จ์œ„ ํ”ฝ์…€์— ๋งž์ถฐ ๊ฐ•์ œ๋กœ ๋Š๋Š” ๊ฒƒ์„ ๋งํ•ด์š”. ๋””์ง€ํ„ธ ํ™”๋ฉด์€ ํ”ฝ์…€ ๋‹จ์œ„๋กœ ๊ทธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—, ์‹ค์ˆ˜ ์ขŒํ‘œ(์˜ˆ: x = 23.6)๋Š” ๋ Œ๋”๋ง ์‹œ ๋ณดํ†ต ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ •์ˆ˜ ํ”ฝ์…€ (24)๋กœ ๋ฐ˜์˜ฌ๋ฆผํ•ด์„œ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

โœ… ์„œ๋ธŒ ํ”ฝ์…€(Subpixel)

์ผ๋ถ€ ๊ทธ๋ž˜ํ”ฝ ์‹œ์Šคํ…œ์€ ์†Œ์ˆ˜์  ๋‹จ์œ„ ์ขŒํ‘œ (์˜ˆ: x = 23.3) ๋„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๊ทธ๋ ค์ค˜์š”. ์ด๊ฑธ "์„œ๋ธŒ ํ”ฝ์…€ ๋ Œ๋”๋ง"์ด๋ผ๊ณ  ํ•ด์š”
→ ๋” ์ •๋ฐ€ํ•œ ์œ„์น˜ ํ‘œํ˜„



๐Ÿ˜ต ๊ทธ๋Ÿฐ๋ฐ ์–‘์žํ™”๋ฅผ ํ•˜๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€?

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ค‘ ์ขŒํ‘œ๊ฐ€ ๋ฏธ์„ธํ•˜๊ฒŒ ์›€์ง์ผ ๋•Œ, ์–‘์žํ™”๋กœ ์ธํ•ด ์ขŒํ‘œ๊ฐ€ 'ํˆญํˆญ ๋Š๊ฒจ์„œ' ๋ณด์ž„ ์ด๊ฒŒ ๋ฐ”๋กœ "์ง€ํ„ฐ(jitter)", ์ฆ‰ ์›€์ง์ž„์ด ๋œ๋œ ๋–จ๋ฆฌ๋Š” ํ˜„์ƒ



๐Ÿ’ฅ "Spring์„ ์•ˆ์ •ํ™”์‹œํ‚ค๊ณ  ์ง€ํ„ฐ๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค"๋Š” ๋œป?

SwiftUI๋‚˜ UI ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ spring animation (์Šคํ”„๋ง ์• ๋‹ˆ๋ฉ”์ด์…˜)์€
→ ๋งˆ์น˜ ํƒ„์„ฑ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์›€์ง์ด๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜

ํ•˜์ง€๋งŒ ์„œ๋ธŒ ํ”ฝ์…€ ์–‘์žํ™”๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด:
์• ๋‹ˆ๋ฉ”์ด์…˜ ๋„์ค‘ ์œ„์น˜๊ฐ€ ์ •์ˆ˜ ํ”ฝ์…€๋กœ๋งŒ ์›€์ง์ด๊ฒŒ ๋˜๋ฉด์„œ ๋œ๋œ ๋–จ๋ฆฌ๊ฑฐ๋‚˜ ๋Š๊ธฐ๋Š” ๋А๋‚Œ(jitter)์ด ๋‚  ์ˆ˜ ์žˆ์–ด์š”.

๊ทธ๋ž˜์„œ ์–‘์žํ™”๋ฅผ ๊บผ์ฃผ๋ฉด:
spring ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋” ๋ถ€๋“œ๋Ÿฝ๊ณ  ์•ˆ์ •์ ์œผ๋กœ ์ž‘๋™ ์ขŒํ‘œ ๋ณ€ํ™”๊ฐ€ ์‹ค์ œ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฐ์†๋œ ๊ฒƒ์ฒ˜๋Ÿผ ํ‘œํ˜„๋จ

 

- Renderer๋กœ ํ…์ŠคํŠธ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•˜๋ ค๋ฉด ์ปค์Šคํ…€ Transition ๊ตฌํ˜„ ํ•„์š” 

- ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜์— ์ด๋ฏธ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์  ๊ณ ๋ ค : ์ด Transition์ด withAnimation์— ๋Œ€ํ•œ ํ˜ธ์ถœ์—์„œ ํŠธ๋ฆฌ๊ฑฐ๋œ ๊ฒฝ์šฐ

 

- ํŠธ๋žœ์žญ์…˜ body view modifier๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ ์ ˆํ•  ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์žฌ์ •์˜ ๊ฐ€๋Šฅ.

- ์ด๋Ÿฌ๋ฉด ๋ชจ๋“  ๋ผ์ธ์— ๋Œ€ํ•ด ๊ท ์ผํ•œ ์„ ํ˜• ํŽ˜์ด์‹ฑ ๋ณด์žฅ.

-> ๋ชจ๋“  ์ค„์ด ๊ฐ™์€ ์†๋„๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋“ฑ์žฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง !!

 

- ๊ทธ ๋‹ค์Œ ์ƒˆ๋กœ์šด textRenderer ๋ทฐ ์ˆ˜์ •์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ „ํ™˜๋˜๋Š” ๋ทฐ์— ์ปค์Šคํ…€ renderer๋ฅผ ์„ค์ •

# ๋ผ์ธ ์ˆ˜์— ์˜์กดํ•˜๋Š” ์ „ํ™˜ ?  ๋ผ์ธ ์ˆ˜๋Š” ๋กœ์ผ€์ผ์ด๋‚˜ Dynamic Type ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ์— ์ฃผ์˜ !

 

- ๊ธ€๋ฆฌํ”„ ๋งˆ๋‹ค ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ. ๊ธ€๋ฆฌํ”„ ? ๊ทธ ๋ฌธ์ž๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊ทธ๋ฆด์ง€ ๊ฒฐ์ •๋œ ๋„ํ˜•

- Text.Layout์˜ run ์Šฌ๋ผ์ด์Šค๋ฅผ ๋ฐ˜๋ณตํ•ด์•ผํ•จ. ์ด ์Šฌ๋ผ์ด์Šค๋Š” ๊ธ€๋ฆฌํ”„๋‚˜ ๋‚ด์žฅ๋œ ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ ๋ ˆ์ด์•„์›ƒ์˜ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„๋ฅผ ๋‚˜ํƒ€๋ƒ„

 

Text.Layout ์•ˆ์—๋Š” run์ด๋ผ๋Š” ๋‹จ์œ„๊ฐ€ ์žˆ์Œ 
run : ์ค„(line) ์•ˆ์—์„œ ๋™์ผํ•œ ์Šคํƒ€์ผ์„ ๊ฐ€์ง„ ์—ฐ์†๋œ ํ…์ŠคํŠธ ์กฐ๊ฐ

์ด run์„ ๋ฐ˜๋ณต(iterate)ํ•˜๋ฉด์„œ ๊ทธ ์•ˆ์— ์žˆ๋Š” ๊ธ€๋ฆฌํ”„(๊ธ€์ž ๋ชจ์–‘) ๋˜๋Š” ์ด๋ฏธ์ง€(์ด๋ชจ์ง€, SF Symbol ๋“ฑ) ๋ฅผ ํ•˜๋‚˜์”ฉ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•จ
์ด๊ฒŒ ํ…์ŠคํŠธ ๋ Œ๋”๋ง์˜ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์ด๊ธฐ ๋•Œ๋ฌธ์— → ์—ฌ๊ธฐ์— ์• ๋‹ˆ๋ฉ”์ด์…˜, ์ƒ‰์ƒ, ๋ณ€ํ˜• ๋“ฑ์„ ๊ฑธ ์ˆ˜ ์žˆ์Œ

๐ŸŽฏ ์™œ run ๋‹จ์œ„๋กœ ๋ฐ˜๋ณตํ•˜๋ƒ?

ํ…์ŠคํŠธ๋ฅผ ์ •๊ตํ•˜๊ฒŒ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด์„œ์˜ˆ์š”.
๊ธ€์ž ํ•˜๋‚˜ํ•˜๋‚˜์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋„ฃ๋Š”๋‹ค๊ฑฐ๋‚˜ ์ด๋ชจ์ง€๋ฅผ ๋”ฐ๋กœ ์›€์ง์ธ๋‹ค๊ฑฐ๋‚˜ ํŠน์ • run๋งŒ ๊ฐ•์กฐ ์ฒ˜๋ฆฌํ•˜๋Š” ๋“ฑ
→ run ๋‹จ์œ„๋กœ ์ ‘๊ทผํ•ด์•ผ ์ปค์Šคํ…€ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

- Text.Layout์€ ๋ผ์ธ์˜ ๋ชจ์Œ. ๋ผ์ธ์€ ๋Ÿฐ์˜ ๋ชจ์Œ์ด๊ณ  , ๋Ÿฐ์€ RunSlice์˜ ๋ชจ์Œ

- flattenedRunSlice๋ผ๋Š” ํ—ฌํผ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด RunSlice๋งŒ ๋ฐ˜๋ณตํ•˜๋ฉด ๋จ. 

- ํ—ฌํผํ•จ์ˆ˜๋Š” line ์ธ์ˆ˜์˜ ์œ ํ˜•๊ณผ ์ด๋ฆ„์„ RunSlice๋กœ ๋ณ€๊ฒฝ

 

 

# ํŠน์ • ๊ธ€์ž๋งŒ ๊ฐ•์กฐ !

 

- TextAttribute ํ”„๋กœํ† ์ฝœ ์‚ฌ์šฉ : iOS18 ๋ฐ ๊ด€๋ จ ๋ฆด๋ฆฌ์ฆˆ์—์„œ TextRenderer์™€ ํ•จ๊ป˜ ๋„์ž…, ์ด ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ•˜๋…€ํ•˜๋ฉด ํ…์ŠคํŠธ์—์„œ TextRenderer๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๊ฐ€๋Šฅ

 

- customAttribute text modifier๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Visual Effects ๋‹จ์–ด๋ฅผ EmphasisAttribute๋กœ ํ‘œ์‹œ.

- ํŠน์ • ๋ฒ”์œ„์˜ ํ…์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๋Š”๋ฐ๋งŒ ์‚ฌ์šฉํ–ˆ์œผ๋ฏ€๋กœ TextAttribute struct์— ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋จ

 

- layout์˜ flattenedRuns ๋ฐ˜๋ณต

- Attribute-Type์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๋Š” ํ•˜์œ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ run์— EmphasisAttribute๊ฐ€ ์žˆ์Œ์„ ํ™•์ธ

1) ์†์„ฑ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ, ์ด์ „๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์Šฌ๋ผ์ด์Šค ๋ฐ˜๋ณต

2) ์†์„ฑ์ด ์—†๋Š” ๊ฒฝ์šฐ, 0.2์ดˆ์— ๊ฑธ์ณ run์—์„œ ๋น ๋ฅด๊ฒŒ ํŽ˜์ด๋“œ ์ธ

 

 

 

๐Ÿ‘ฅ Metal shaders

- shader : ๋‹ค์–‘ํ•œ ๋ Œ๋”๋ง ํšจ๊ณผ๋ฅผ ๊ธฐ๊ธฐ์˜ GPU์—์„œ ๋ฐ”๋กœ ๊ณ„์‚ฐํ•˜๋Š” ์ž‘์€ ํ”„๋กœ๊ทธ๋žจ

- SwiftUI์—์„œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์…ฐ์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์‹œ๊ฐํšจ๊ณผ ๊ตฌํ˜„

- iOS 17 ์— ๋„์ž…๋œ SwiftUI ์…ฐ์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์€ ์œ ์ง€ํ•˜๋ฉด์„œ ์‹œ๊ฐํšจ๊ณผ ์ž‘์„ฑ ๊ฐ€๋Šฅ.

 

- SwiftUI์—์„œ Shader๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๋ ค๋ฉด ShaderLibrary์—์„œ Shader์˜ ์ด๋ฆ„์„ ๊ฐ–๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋จ.

- ์ถ”๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ Shaderํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Œ. ์ƒ‰์ƒ, ์ˆซ์ž, ์ด๋ฏธ์ง€ 

- layerEffect๋กœ ๋ทฐ์— ์ด ํšจ๊ณผ ์ ์šฉ : SwiftUI๊ฐ€ ๋ทฐ์˜ ๋ชจ๋“  ํ”ฝ์…€์— ๋Œ€ํ•ด Shaderํ•จ์ˆ˜ ํ˜ธ์ถœ

 

๋งŽ์€ ํ”ฝ์…€์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Shader๋Š” ๊ณ ๋„๋กœ ๋ณ‘๋ ฌํ™”๋œ ์ž‘์—…์— ์ตœ์ ํ™”๋œ ๊ธฐ๊ธฐ์˜ GPU์—์„œ ์‹คํ–‰๋จ
GPUํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์„ฑ ์ƒ Shader์ž์ฒด๋Š” Swift ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์—†์Œ.

 

-> Metal Shading Language ๋กœ ์ž‘์„ฑ. ( Metal ์ด๋ผ๊ณ  ํ•จ )

 

 

Shader์˜ Metal ํŒŒ์ผ : Shaderํ•จ์ˆ˜์˜ ์ด๋ฆ„์ด ShaderLibrary์—์„œ ํ˜ธ์ถœํ•œ ๊ฒƒ๊ณผ ์ผ์น˜

- SwiftUI๋Š” ๊ฐ ๋ทฐ์˜ ํ”ฝ์…€์— ๋Œ€ํ•ด ์ด ํ•จ์ˆ˜๋ฅผ GPU์—์„œ ์‹คํ–‰ 

- ์‹คํ–‰ ์‹œ position์€ ํ•ด๋‹น ํ”ฝ์…€์˜ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋ƒ„ 

- layer๋Š” ๋ทฐ ์ฝ˜ํ…์ธ ๋ฅผ ๋‚˜ํƒ€๋ƒ„ 

- ๋ ˆ์ด์–ด๋ฅผ ์ƒ˜ํ”Œ๋งํ•ด์„œ ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ Shader๊ฐ€ ์ธ์Šคํ„ด์Šคํ™”๋œ maxSampleOffset ๋‚ด์— ๋จธ๋ฌผ๋Ÿฌ์•ผ ํ•จ

 


- SwiftUI๋Š” ์ƒ‰์ƒ๊ณผ ๊ฐ™์€ ์œ ํ˜•์„ Metal ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œํ˜„์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ณ  ๋ณ€ํ™˜.

์˜ˆ : ๋ถ„ํ™์ƒ‰ -> half4

- Metal์€ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋ฒกํ„ฐ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉ.

- half4๋Š” 16๋น„ํŠธ ๋ถ€๋™ ์†Œ์ˆ˜์  ์ˆซ์ž ํฌํ•จ, 4๊ฐœ์˜ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๊ฐ–๋Š” ๋ฒกํ„ฐ

- ์ด ์œ ํ˜•์€ ๋นจ๊ฐ•, ๋…น์ƒ‰ , ํŒŒ๋ž‘ ๋ฐ ์•ŒํŒŒ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์ธ์ฝ”๋”ฉ. 

- float2 ๋Š” 32๋น„ํŠธ ๋ถ€๋™ ์†Œ์ˆ˜์  ์ˆซ์ž๋ฅผ ํฌํ•จ. 2๊ฐœ์˜ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๊ฐ–๋Š” ๋ฒกํ„ฐ๋กœ 2D ์ ์ด๋‚˜ ์ฐจ์›์— ์ฃผ๋กœ ์‚ฌ์šฉ

 

- SwiftUI์—์„œ Shader๋Š” 

 

1. Custom Fills

2. Color Effects

3. Distortion effects

4. Layer effects 

 

์œ„ ํšจ๊ณผ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

3๊ฐ€์ง€ ํšจ๊ณผ์ค‘ ๋ ˆ์ด์–ด ํšจ๊ณผ๊ฐ€ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๋‘ ํšจ๊ณผ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Œ

 

- ์‚ฌ์šฉ์ž๊ฐ€ ๋ทฐ๋ฅผ ํƒญํ•  ๋•Œ๋งˆ๋‹ค ํŠธ๋ฆฌ๊ฑฐ ๋˜๋Š” ํ‘ธ์‹œ ํšจ๊ณผ๊ฐ€ ์ ์šฉ๋˜์–ด ์žˆ์Œ

- ๋ทฐ๋Š” spring์„ ํ†ตํ•ด ํฌ๊ธฐ๊ฐ€ ์ž‘์•„์ง€๋‹ค๊ฐ€ ์ฆ‰์‹œ ๋‹ค์‹œ ์˜ฌ๋ผ์˜ด.

 

=> ํ•˜์ง€๋งŒ, ํƒญํ•˜๋Š” ์œ„์น˜์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์‘๋‹ตํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ธ์œ„์ ์ด๊ณ  ๊ฒฝ์ง๋œ ๋А๋‚Œ ? 

๐Ÿ’ฌ ๋ทฐ๋ฅผ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ๋ˆ„๋ฅธ ์œ„์น˜์—์„œ๋ถ€ํ„ฐ ์Šค์ผ€์ผ ํšจ๊ณผ๊ฐ€ ๋ฐ”๊นฅ์ชฝ์œผ๋กœ ํผ์ง€๋„๋ก ํ•˜๊ณ  ์‹ถ๋‹ค !

: Shader๋กœ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

- Metal ํŒŒ์ผ์— ์ƒˆ ์…ฐ์ด๋” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ : Ripple

- ๋ ˆ์ด์–ด ํšจ๊ณผ์˜ API์— ํ•„์š”ํ•œ ์ธ์ˆ˜ 2๊ฐ€์ง€ ์ถ”๊ฐ€ : position, layer

- ๋ทฐ๊ฐ€ ๋ˆŒ๋ฆฐ ์ง€์ , ๊ฒฝ๊ณผ๋œ ์‹œ๊ฐ„, ๊ทธ ์™ธ 4๊ฐœ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ํ•จ์ˆ˜

- ํ”ฝ์…€์— ๋Œ€ํ•œ ์™œ๊ณก์„ ๊ณ„์‚ฐํ•˜์—ฌ ์ƒˆ๋กœ์šด newPosition์„ ์–ป์Œ => ๋ทฐ๋ฅผ ์ƒ˜ํ”Œ๋ง

- ์™œ๊ณก์— ๋”ฐ๋ผ ์•ฝ๊ฐ„์˜ ์กฐ์ • ํ›„ ์ˆ˜์ •๋œ ์ƒ‰์ƒ์„ ๋ฐ˜ํ™˜ 

 

- SwiftUI์—์„œ ์…ฐ์ด๋” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด RippleModifier๋ผ๋Š” ViewModifier๋ฅผ ๋งŒ๋“ฌ

- ์…ฐ์ด๋” ํ•จ์ˆ˜์˜ ๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ SwiftUI์— ๋…ธ์ถœ.

- body(content:) ๋ฉ”์†Œ๋“œ์—์„œ ์…ฐ์ด๋”๋ฅผ ์ธ์Šคํ„ด์Šคํ™” ํ•˜๊ณ  ์ด๋ฅผ ์ฝ˜ํ…์ธ ์— ์ ์šฉ

- ์…ฐ์ด๋”์—๋Š” ์‹œ๊ฐ„ ๊ฐœ๋…์ด ์—†์Œ. SwiftUI์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ž‘๋™์‹œ์ผœ์•ผํ•จ 

 

- RippleEffect ๋ผ๋Š” ViewModifier๋ฅผ ์ž‘์„ฑ

: keyframeAnimator ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ œ์Šค์ฒ˜์™€ ๊ฐ™์ด ์™ธ๋ถ€ ๋ณ€ํ™”๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹คํ–‰ ๊ฐ€๋Šฅ

- ํŠธ๋ฆฌ๊ฑฐ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋  ๋•Œ ๋งˆ๋‹ค 0์—์„œ ์ตœ์ข… ์ง€์† ์‹œ๊ฐ„ ๊ฐ’๊นŒ์ง€ elapsedTime์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ

- ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ๋ชจ๋“  ๋‹จ๊ณ„์—์„œ ํ˜„์žฌ ์‹œ๊ฐ„๊ณผ ๋ณด๊ธฐ๋ฅผ ๋ˆ„๋ฅธ ์›๋ž˜ ์ง€์ ์„ RippleModifier์— ์ „๋‹ฌ.

 

4๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์„ ํ• ๋‹นํ•ด๋ณด๋Š” ์‹คํ—˜ : ์–ด๋–ค ๊ฐ’์ด ์ข‹์„์ง€.

- ๋””๋ฒ„๊ทธ UI๋ฅผ ๋นŒ๋“œ.

ํœด๋Œ€ํฐ์ด๋‚˜ ์—‘์ฝ” ๋ฏธ๋ฆฌ๋ณด๊ธฐ์—์„œ ์…ฐ์ด๋” ๊ธฐ๋Šฅ์— ์ ํ•ฉํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ž…๋ ฅ ๊ฐ€๋Šฅ

- ๋””๋ฒ„๊ทธ UI๋Š” ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ฐ˜๋ณตํ•  ๋•Œ ์œ ์šฉ !!

- ๋งค๊ฐœ๋ณ€์ˆ˜ ๋…ธ์ถœ, ์ค‘๊ฐ„ ๊ฐ’์„ ์‹œ๊ฐํ™”ํ•˜๋Š” ์˜ค๋ฒ„๋ ˆ์ด ๊ทธ๋ฆฌ๊ธฐ.

- ํ”ผ๋“œ๋ฐฑ : ์œ ์šฉ, ์…ฐ์ด๋” ์ž‘์—…์€ ๋ฌด๊ถ๋ฌด์ง„

 

 

 

์ด๋ฒˆ ์„ธ์…˜์—์„œ๋Š” SwiftUI๋กœ ์‹œ๊ฐํšจ๊ณผ๋ฅผ ๋งŒ๋“œ๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜๋Š”๋ฐ์š”.

์ƒ๊ฐ๋ณด๋‹ค ์–‘์ด ๋งŽ๊ณ , ๋‚ด์šฉ์ด ๊ตฌ์ฒด์ ์ด์—ˆ๋„ค์š”... ! ์‹ค์ œ๋กœ ์ œ๊ฐ€ ์ด๋ ‡๊ฒŒ ๊นŠ๊ฒŒ ์‚ฌ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ์„์ง„ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ~

๋ชฌ๊ฐ€ ์ด๊ฒƒ์ €๊ฒƒ ์‹ ๊ธฐํ•œ ์„ธ์…˜์ด์—ˆ์Šต๋‹ˆ๋‹ค :)

 

 

๋ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. 

๋ฐ˜์‘ํ˜•