[Flutter]Animation Route

한상욱·2024년 7월 23일
0

Flutter

목록 보기
14/26
post-thumbnail

들어가며

Flutter 에서는 MaterialPageRoute를 이용하여 각 플랫폼에 맞는 라우팅을 제공하고 있습니다. 하지만, 요구사항에 따라서 여러가지 네비게이션 효과를 구현해야 되는 경우가 있는데요. 이러한 경우에 네비게이션에 애니메이션 효과를 줄 수 있습니다.

기본 환경 구축

가장 기본적으로 네비게이션을 위한 두개의 페이지 위젯을 제작해보겠습니다.

//main.dart
import ...

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: App(),
    );
  }
}

페이지 이동은 App.dart로부터 시작됩니다. 간단하게 Text와 ElevatedButton위젯으로 구현해보겠습니다.

//app.dart
import ...

class App extends StatelessWidget {
  const App({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Animation Page Routing"),
      ),
      body: Center(
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("첫번째 페이지"),
          ElevatedButton(
              onPressed: () {
				// 네비게이션 함수
              },
              child: const Text("두번째 페이지로"))
        ],
      )),
    );
  }
}

페이지 이동 후 도달하게 되는 페이지입니다. 이 페이지에서는 간단하게 뒤로가기 버튼 활성화를 위해 AppBar, 두번째 페이지를 의미하는 Text 위젯만 존재합니다.

import ...

class Second extends StatelessWidget {
  const Second({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: const Center(
        child: Text("두번째 페이지"),
      ),
    );
  }
}

PageRouteBuilder

PageRouteBuilder는 간단하게 네비게이션 애니메이션을 줄 수 있는 위젯입니다. 이를 이용해서 여러 형식의 네비게이션을 한번 만들어 보겠습니다.

import ...

class App extends StatelessWidget {
  const App({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Animation Page Routing"),
      ),
      body: Center(
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("첫번째 페이지"),
          ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(PageRouteBuilder(
                  pageBuilder: (context, animation, secondaryAnimation) =>
                      const Second(),
                ));
              },
              child: const Text("두번째 페이지로"))
        ],
      )),
    );
  }
}

아무런 효과도 지정하지 않은 Plain 형식의 PageRouteBuilder입니다. 이렇게 되면 페이지가 바로바로 이동하게 됩니다.

Slide Animation

이제 Slide Animation을 가진 네비게이션을 생성해보겠습니다. PageRouteBuilder에 큰 장점은 이것을 너무나 쉽게 만들 수 있게 해줍니다.

import 'package:flutter/material.dart';
import 'package:flutter_animation_navigation/src/pages/second.dart';

class App extends StatelessWidget {
  const App({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Animation Page Routing"),
      ),
      body: Center(
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("첫번째 페이지"),
          ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(PageRouteBuilder(
                  pageBuilder: (context, animation, secondaryAnimation) =>
                      const Second(),
                      // transition 정의
                  transitionsBuilder:
                      (context, animation, secondaryAnimation, child) {
                    const begin = Offset(0.0, -1.0);
                    const end = Offset.zero;
                    final tween = Tween(begin: begin, end: end);
                    final offsetAnimation = animation.drive(tween);
                    return SlideTransition(
                        position: offsetAnimation, child: child);
                  },
                ));
              },
              child: const Text("두번째 페이지로"))
        ],
      )),
    );
  }
}

transitionBuilder를 통해 여러가지 애니메이션을 지정할 수 있습니다. 지금 애니메이션은 아래에서 위로 페이지가 등장하게 됩니다. Offset을 조절하면 여러 방향에서 페이지를 이동시킬 수 있습니다.

Curve Animation

기본적인 Transition은 동일한 속도로 페이지가 이동하는데, 만약 속도의 변화를 곡선의 형태로 나타내고 싶다면 Curve를 이용할 수 있습니다. 점점 빨라지거나 점점 느려지는 것을 구현할 수 있습니다.

import ...

class App extends StatelessWidget {
  const App({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Animation Page Routing"),
      ),
      body: Center(
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("첫번째 페이지"),
          ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(PageRouteBuilder(
                  pageBuilder: (context, animation, secondaryAnimation) =>
                      const Second(),
                  transitionsBuilder:
                      (context, animation, secondaryAnimation, child) {
                    const begin = Offset(0.0, 1.0);
                    const end = Offset.zero;
                    const curve = Curves.ease;

                    var tween = Tween(begin: begin, end: end)
                        .chain(CurveTween(curve: curve));
                    final tweenAnimation = animation.drive(tween);
                    return SlideTransition(
                        position: tweenAnimation, child: child);
                  },
                ));
              },
              child: const Text("두번째 페이지로"))
        ],
      )),
    );
  }
}

Curve의 종류를 변경하면 여러가지 속도 곡선을 이용할 수 있습니다.

Fade Transition

Fade 효과를 나타내기 위해서는 Fade Transition을 이용할 수 있습니다.

class App extends StatelessWidget {
  const App({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Animation Page Routing"),
      ),
      body: Center(
          child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("첫번째 페이지"),
          ElevatedButton(
              onPressed: () {
                Navigator.of(context).push(PageRouteBuilder(
                  pageBuilder: (context, animation, secondaryAnimation) =>
                      const Second(),
                  transitionsBuilder:
                      (context, animation, secondaryAnimation, child) {
                    return FadeTransition(opacity: animation, child: child);
                  },
                ));
              },
              child: const Text("두번째 페이지로"))
        ],
      )),
    );
  }
}

FadeTransition 위젯은 Fade 효과를 표현할 수 있습니다.

profile
자기주도적, 지속 성장하는 모바일앱 개발자가 되기 위해

0개의 댓글