๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Flutter + Dart/Flutter + Dart ๊ณต๋ถ€

์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ธฐ์ดˆ ํ•™์Šต ๋ฐ ํ”Œ๋žซํผ๋ณ„ UI ์ดํ•ด

by GREEN๋‚˜๋ฌด 2025. 5. 16.
728x90

 

๐Ÿ“Œ ํ•™์Šต ๋ชฉํ‘œ

  • Flutter์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ์Šคํ…œ์„ ์ดํ•ดํ•˜๊ณ  ๊ฐ„๋‹จํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Android(Material), iOS(Cupertino)์˜ ํ”Œ๋žซํผ๋ณ„ UI ์ฐจ์ด๋ฅผ ์ดํ•ดํ•˜๊ณ , ํ”Œ๋žซํผ์— ๋”ฐ๋ผ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ธฐ์ดˆ๋ฅผ ๋ฐฐ์šด๋‹ค.

๐Ÿ“š ์ฃผ์š” ๊ฐœ๋… ์š”์•ฝ

1. Flutter ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ

Flutter์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ํ•ต์‹ฌ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋จ:

๊ฐœ๋… ์„ค๋ช…
AnimationController ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ์‹คํ–‰/์ •์ง€/์‹œ๊ฐ„์„ ์ œ์–ดํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ. ํ”„๋ ˆ์ž„ ๋‹จ์œ„๋กœ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•จ.
Tween ์‹œ์ž‘ ๊ฐ’๊ณผ ๋ ๊ฐ’์„ ์„ค์ •ํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ๊ฐ์ฒด. ์˜ˆ: 0~1, ์ƒ‰์ƒ ๋ณ€ํ™” ๋“ฑ
AnimatedWidget ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒํƒœ์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ๊ทธ๋ ค์ง€๋Š” ์œ„์ ฏ. ๋งค๋ฒˆ setState() ํ˜ธ์ถœ ํ•„์š” ์—†์Œ.

2. ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ์œ„์ ฏ

์œ„์ ฏ๋ช… ์„ค๋ช… ์˜ˆ์‹œ ์‚ฌ์šฉ์ฒ˜
FadeTransition ํˆฌ๋ช…๋„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ™”๋ฉด ์ „ํ™˜ ์‹œ ํŽ˜์ด๋“œ ์ธ/์•„์›ƒ
SizeTransition ์œ„์ ฏ ํฌ๊ธฐ ๋ณ€๊ฒฝ ๋ฒ„ํŠผ ํ™•๋Œ€/์ถ•์†Œ ์• ๋‹ˆ๋ฉ”์ด์…˜
SlideTransition ์œ„์ ฏ ์œ„์น˜ ์ด๋™ ์Šฌ๋ผ์ด๋“œ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ๋ฉ”๋‰ด

3. ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ๋ฆ„ ๊ฐ„๋‹จ ์˜ˆ์‹œ

AnimationController์™€ Tween์„ ํ™œ์šฉํ•ด์„œ ํŽ˜์ด๋“œ ์ธ(์ ์  ๋ณด์ด๊ธฐ) ํšจ๊ณผ๋ฅผ ๊ตฌํ˜„ํ•œ ์˜ˆ์ œ

class MyFadeWidget extends StatefulWidget {
  @override
  _MyFadeWidgetState createState() => _MyFadeWidgetState();
}

/// ์ƒํƒœ ํด๋ž˜์Šค, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค์„ ๋‹ด๋‹น
class _MyFadeWidgetState extends State<MyFadeWidget> with SingleTickerProviderStateMixin {
  late AnimationController _controller; // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ ์„ ์–ธ
  late Animation<double> _animation; // ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ’ (ํˆฌ๋ช…๋„)

  @override
  void initState() {
    super.initState();

    // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ ์ƒ์„ฑ with 2์ดˆ ์ง€์† ์‹œ๊ฐ„
    _controller = AnimationController(
      vsync: this, // TickerProvider๋ฅผ ํ†ตํ•ด ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ”„๋ ˆ์ž„ ๋™๊ธฐํ™”
      duration: Duration(seconds: 2),
    );

    // Tween์„ ์‚ฌ์šฉํ•˜์—ฌ 0์—์„œ 1๊นŒ์ง€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ’ ์ „๋‹ฌ
    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);

    _controller.forward(); // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ์ž‘(ํŽ˜์ด๋“œ ์ธ ํšจ๊ณผ)
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _animation, // ์• ๋‹ˆ๋ฉ”์ด์…˜์— ๋”ฐ๋ผ ํˆฌ๋ช…๋„ ๋ณ€ํ™”
      child: Text('Hello, Flutter!'), // ๋ณด์—ฌ์ค„ ํ…์ŠคํŠธ ์œ„์ ฏ
    );
  }

  @override
  void dispose() {
    _controller.dispose(); // ๋ฆฌ์†Œ์Šค ํ•ด์ œ
    super.dispose();
  }
}

๐Ÿงช ์‹ค์Šต ๊ณผ์ œ ์˜ˆ์‹œ

1. ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ƒ‰์ƒ ๋ณ€๊ฒฝ ์• ๋‹ˆ๋ฉ”์ด์…˜

  • AnimatedContainer๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ƒ‰์ƒ, ํฌ๊ธฐ, ์—ฌ๋ฐฑ ๋“ฑ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๋ณ€๊ฒฝ
AnimatedContainer(
  duration: Duration(seconds: 1),
  color: _isClicked ? Colors.blue : Colors.red,
  width: 200,
  height: 100,
  child: ElevatedButton(
    onPressed: () {
      setState(() {
        _isClicked = !_isClicked;
      });
    },
    child: Text('ํด๋ฆญ'),
  ),
);

2. ํ™”๋ฉด ์ „ํ™˜ ์‹œ ํŽ˜์ด๋“œ ํšจ๊ณผ ์ ์šฉ

Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => SecondPage(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return FadeTransition(
        opacity: animation,
        child: child,
      );
    },
  ),
);

๐Ÿ“ฑ ํ”Œ๋žซํผ๋ณ„ UI ์ดํ•ด (์„ ํƒ)

ํ”Œ๋žซํผ ๋””์ž์ธ ์‹œ์Šคํ…œ Flutter ๋Œ€์‘ ์œ„์ ฏ ์˜ˆ์‹œ
Android Material Design Scaffold, AppBar, ElevatedButton
iOS Cupertino CupertinoPageScaffold, CupertinoButton

ํ”Œ๋žซํผ๋ณ„ UI ๊ตฌํ˜„ ์‹œ ์กฐ๊ฑด ๋ถ„๊ธฐ:

Widget build(BuildContext context) {
  if (Platform.isIOS) {
    return CupertinoButton(child: Text('iOS ๋ฒ„ํŠผ'), onPressed: () {});
  } else {
    return ElevatedButton(child: Text('Android ๋ฒ„ํŠผ'), onPressed: () {});
  }
}

๋˜๋Š” flutter_platform_widgets ํŒจํ‚ค์ง€ ํ™œ์šฉ.


๐Ÿงพ ์ •๋ฆฌ๋œ ์ฃผ์š” ์œ„์ ฏ/ํด๋ž˜์Šค/์†์„ฑ ํ‘œ

๋ถ„๋ฅ˜  ์ด๋ฆ„ ์„ค๋ช…
์• ๋‹ˆ๋ฉ”์ด์…˜ ์ œ์–ด AnimationController ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ˆ˜๋™์œผ๋กœ ์ œ์–ดํ•จ
์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ’ ์ƒ์„ฑ Tween<T> ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฒ”์œ„ ์„ค์ • (ex. 0 ~ 1, ์ƒ‰์ƒ)
์ž๋™ ์œ„์ ฏ ๊ฐฑ์‹  AnimatedWidget ๋‚ด๋ถ€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ž๋™ ๊ฐฑ์‹ 
์œ„์ ฏ ์• ๋‹ˆ๋ฉ”์ด์…˜ AnimatedContainer ์†์„ฑ ๋ณ€๊ฒฝ ์‹œ ์ž๋™ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ
์œ„์ ฏ ์• ๋‹ˆ๋ฉ”์ด์…˜ FadeTransition ํˆฌ๋ช…๋„ ๋ณ€๊ฒฝ ์• ๋‹ˆ๋ฉ”์ด์…˜
์œ„์ ฏ ์• ๋‹ˆ๋ฉ”์ด์…˜ SizeTransition ์œ„์ ฏ ํฌ๊ธฐ ๋ณ€๊ฒฝ ์• ๋‹ˆ๋ฉ”์ด์…˜
์œ„์ ฏ ์• ๋‹ˆ๋ฉ”์ด์…˜ SlideTransition ์œ„์น˜ ์ด๋™ ์• ๋‹ˆ๋ฉ”์ด์…˜
์• ๋‹ˆ๋ฉ”์ด์…˜ ์ปค๋ธŒ CurvedAnimation ์†๋„ ๊ณก์„  ์ ์šฉ (ex. ease-in, bounce ๋“ฑ)

๐Ÿ”— ์ฐธ๊ณ  ๋งํฌ