Flutter

Segment ๋ฒ„ํŠผ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉํ•˜๊ธฐ

flutter developer 2025. 1. 25. 16:41

๐Ÿง Before

์„ธ๊ทธ๋จผํŠธ ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•˜๋˜์ค‘ ํƒญํ–ˆ์„๋•Œ ๋ณ€ํ™”๊ฐ€ ๋„ˆ๋ฌด ๋‹จ์กฐ๋กญ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ์˜ˆ์˜๊ฒŒ ๊พธ๋ฏธ๊ณ ์‹ถ์–ด ์„ธ๊ทธ๋จผํŠธ ๋ฒ„ํŠผ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋„ฃ์–ด๋ณด์•˜๋‹ค.


โ˜บ๏ธ After

 

์• ๋‹ˆ๋ฉ”์ด์…˜ 1

 

์„ธ๊ทธ๋จผํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ AnimatedContainer์„ ํ†ตํ•ด ๊ตฌํ˜„ํ–ˆ๋‹ค. AnimatedContainer๋Š” ์ƒ‰์ƒ, ํฌ๊ธฐ, ๋ชจ์–‘, ์œ„์น˜ ๋“ฑ ์†์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ž๋™์œผ๋กœ ์ ์šฉํ•ด์ค€๋‹ค. ๋ณ„๋„์˜ ์ปจํŠธ๋กค๋Ÿฌ ์—†์ด duration๊ณผ curve๋งŒ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค๋Š”๊ฒŒ ํฐ ์žฅ์ ์ด๋‹ค. ์œ„ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ํฌ๊ฒŒ ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ์ƒ‰ ๋ณ€ํ™”์™€ ํ…์ŠคํŠธ์ƒ‰ ๋ณ€ํ™”๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. 

๋ฐฐ๊ฒฝ์ƒ‰ ๋ณ€ํ™”

  • duration: ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ์ง€์† ์‹œ๊ฐ„(300ms). ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ƒ‰์ƒ์ด ์ฒœ์ฒœํžˆ ๋ณ€๊ฒฝ
  • curve: ์• ๋‹ˆ๋ฉ”์ด์…˜ ์†๋„ ๊ณก์„ . Curves.easeInOut์€ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์‹œ์ž‘ํ•˜๊ณ  ์ผ๋ฐ˜์ ์ธ ์†๋„๋กœ ์ข…๋ฃŒ.
  • ๋ฐฐ๊ฒฝ์ƒ‰์ƒ ์ „ํ™˜: isSelected์— ๋”ฐ๋ผ AppColors.primary.blue ๋˜๋Š” AppColors.base.deep๋กœ ๋ณ€๊ฒฝ

AnimatedDefaultTextStyle์€ ํ…์ŠคํŠธ์˜ ์Šคํƒ€์ผ(์˜ˆ: ์ƒ‰์ƒ, ๊ตต๊ธฐ)์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. Animation Container์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ duration๊ณผ curve๋งŒ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

 

ํ…์ŠคํŠธ์ƒ‰ ๋ณ€ํ™”

  • ํ…์ŠคํŠธ ์ƒ‰์ƒ ๋ณ€๊ฒฝ: ์„ ํƒ๋œ ๋ฒ„ํŠผ์—์„œ๋Š” AppColors.base.white๋กœ ๋ณ€๊ฒฝ.
  • ํ…์ŠคํŠธ ๊ตต๊ธฐ ๋ณ€๊ฒฝ: ์„ ํƒ๋œ ๋ฒ„ํŠผ์—์„œ๋Š” FontWeight.bold๋กœ ๊ฐ•์กฐ.

 

์•ก์…˜์ฃผ๊ธฐ

selectedIndex๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ์„ ํƒ๋œ ๋ฒ„ํŠผ์˜ ์ธ๋ฑ์Šค๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค. ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด setState๋กœ selectedIndex๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ , ์ด๋ฅผ ํ†ตํ•ด ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์‹œ์ž‘๋œ๋‹ค. AnimatedContainer์™€ AnimatedDefaultTextStyle์€ ์ƒํƒœ๊ฐ’(isSelected)์— ๋”ฐ๋ผ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ํŠธ๋ฆฌ๊ฑฐ ๋œ๋‹ค.

 

์ „์ฒด์ฝ”๋“œ ๋งํฌ https://gist.github.com/suojae/0fbd7f17467f9560a737e6b5ecbc49b4

 

 

 

์• ๋‹ˆ๋ฉ”์ด์…˜ 2

 

๋‘๋ฒˆ์งธ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ AnimatedPositioned์™€ Stack์„ ํ™œ์šฉํ•ด ๋ฒ„ํŠผ ์„ ํƒ ์‹œ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ด๋™ํ•˜๋Š” ์Šฌ๋ผ์ด๋”ฉ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•ด๋ณด์•˜๋‹ค. ์Šฌ๋ผ์ด๋”ฉ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ์ฒซ๋ฒˆ์งธ์™€ ๋‹ฌ๋ฆฌ ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ์—๋งŒ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ฃผ๊ณ  ํ…์ŠคํŠธ์ƒ‰์—๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์•ˆ์ฃผ๊ณ  ์ƒ‰๋ณ€ํ™”๋งŒ ์ฃผ์—ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋จผ์ € ๋‘ ๋ ˆ์ด์–ด๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ–ˆ๋‹ค.

 

 

Stack ์œ„์ ฏ์„ ์‚ฌ์šฉํ•ด ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ๊ณผ ํ…์ŠคํŠธ ๋ ˆ์ด์–ด ๋ถ„๋ฆฌ

๋ฐฐ๊ฒฝ์ƒ‰์€ ๋‹จ์ˆœํžˆ ์ƒ‰๋ณ€ํ™”๊ฐ€ ์•„๋‹Œ ์œ„์น˜๊ฐ€ ๋ฐ”๋€Œ์–ด์•ผํ–ˆ๊ธฐ๋•Œ๋ฌธ์— Stack ์œ„์ ฏ์„ ์‚ฌ์šฉํ•ด ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ๊ณผ ํ…์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ๋œ ๋ ˆ์ด์–ด๋กœ ๊ตฌ์„ฑํ›„ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•ด์ฃผ์—ˆ๋‹ค.

 

๋ฐฐ๊ฒฝ์ƒ‰ ๋ณ€ํ™”

 

๋ฒ„ํŠผ์˜ ๊ฐœ์ˆ˜์— ๋”ฐ๋ผ ๋ฐฐ๊ฒฝ์˜ ํฌ๊ธฐ์™€ ์œ„์น˜๋ฅผ ๋™์ ์œผ๋กœ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด LayoutBuilder๋ฅผ ํ™œ์šฉํ–ˆ๋‹ค. constraints.maxWidth๋กœ ์ „์ฒด ๋„ˆ๋น„๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๋ฒ„ํŠผ ๊ฐœ์ˆ˜๋กœ ๋‚˜๋ˆ„์–ด ๋ฒ„ํŠผ ํ•˜๋‚˜์˜ ๋„ˆ๋น„(buttonWidth)๋ฅผ ๊ตฌํ•œ ํ›„  ์„ ํƒ๋œ ์ธ๋ฑ์Šค * buttonWidth ๋งŒํผ ์™ผ์ชฝ ์œ„์น˜๋ฅผ ์ •ํ•ด์ฃผ์–ด ํŒŒ๋ž€ ๋ฐ•์Šค ๋ฐ์ฝ”๋ ˆ์ด์…˜์„ ์ฑ„์›Œ์ฃผ์—ˆ๋‹ค. ์ด๋•Œ ์œ„์น˜๋ณ€ํ™”์— ๋”ฐ๋ฅธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ฃผ์–ด์•ผํ–ˆ์–ด์„œ ์œ„์น˜์— ๋”ฐ๋ฅธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ž๋™์œผ๋กœ ์ฃผ๋Š” AnimatedPositioned ์œ„์ ฏ์„ ํ†ตํ•ด ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

ํ…์ŠคํŠธ์ƒ‰ ๋ณ€ํ™”

ํ…์ŠคํŠธ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์—†์ด GestureDetector๋ฅผ ํ†ตํ•ด ํƒญํ•  ๋•Œ๋งˆ๋‹ค setState()๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋‹จ์ˆœ ์ƒ‰๋ณ€ํ™”๋งŒ ์ฃผ์—ˆ๋‹ค.

 

์• ๋‹ˆ๋ฉ”์ด์…˜02 ์ „์ฒด์ฝ”๋“œ: https://gist.github.com/suojae/554c72bb7d2a484df5e7ce0730777333

 

 

์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ์„ ํƒ๋œ ๋ฒ„ํŠผ์œผ๋กœ ๋ฐฐ๊ฒฝ์ด ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์Šฌ๋ผ์ด๋”ฉํ–ˆ๊ณ  ์„ ํƒ๋œ ํ…์ŠคํŠธ๋Š” ํ•˜์ด๋ผ์ดํŠธ ์ƒ‰์ƒ๊ณผ ๊ตต์€ ํ…์ŠคํŠธ๋กœ ํ‘œ์‹œํ•˜์—ฌ ์˜ˆ์œ ์„ธ๊ทธ๋จผํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ฝ”๋”ฉ๋ฉด์—์„œ๋Š” 2๋ฒˆ์ด ์ข€๋” ์ž‘์—…์ด ๋“ค์–ด๊ฐ”์ง€๋งŒ ๋ง‰์ƒ ๋น„๊ตํ•ด๋ณด๋‹ˆ ๊ฒฐ๊ณผ์ ์œผ๋กœ๋Š” 1๋ฒˆ์ด ๋” ์˜ˆ์œ ๊ฒƒ ๊ฐ™๋‹ค๐Ÿฅน