본문 바로가기
프로그래밍/Flutter

[Flutter Layout] 17. 플러터 Hero 위젯 애니메이션(화면 전환시 애니메이션 넣기)

by 신나요 2022. 4. 26.

화면이 전환될 때 애니메이션과 화면이 바뀌면 자연스러운 사용자 경험을 제공할 수 있습니다. Hero 위젯으로 화면이 전환되면서 애니메니션을 보여주는 방법을 익혀보겠습니다.


프로젝트 만들기

VSCode에서 new project로 herodemo라는 새로운 앱을 만들겠습니다.

잠시 후 플러터의 기본 코드가 자동으로 생성이 됩니다.

앱의 시작 코드가 들어있는 main.dart에서 MyApp클래스를 제외한 모든 불필요한 코드를 삭제하겠습니다.

불필요한 코드를 정리해 주었고 MyApp 위젯에서 home 속성에 HeroPage를 설정하고 있습니다.

 

HeroPage

HeroPage 클래스를 작성하겠습니다.

HeroPage Stateless위젯으로 build메소드에서 Scaffold를 반환해 주고 있습니다. body는 Container를 설정해 주었고, child는 사용자가 클릭할 세 개의 이미지가 포함될 Row를 설정해 주었습니다.

 

만들 앱의 이미지 

지금부터 만들 앱의 이미지를 떠올려 보면, 메인화면의 화면 상단에 3개의 클릭할 수 있는 이미지가 있고, 각 이미지를 클릭하면 이미지의 디테일 화면으로 이동하는 앱을 생각하고 있습니다.

Row에는 사용자가 선택할 세개의 이미지를 넣어주어야 하고, 애니메이션에 관련된 코드도 이곳에 작성해 주어야 합니다.

 

util.dart

HeroPage을 완성하기 전에 프로젝트 전체에서 사용할 util.dart파일을 만들겠습니다.

Util 클래스는 이미지의 URL를 가지는 세 개의 정적 필드와 buildHeroIcon이라는 정적 메서드를 가지고 있습니다. url에 대한 static 변수는 기본 화면과 세부 정보화면에 아이콘을 표시할 때 사용할 예정입니다. buildHeroIcon 메소드는 path와, tag를 인수로 전달받고  Hero 위젯을 리턴해 주고 있습니다. 리턴할 Hero 위젯은 인수로 건네받은 tag와 path를 바탕으로 tag설정을 하고 child에 가로 세로 80 크기를 가지고,  path로 이미지 설정하는 SizedBox를 설정하고 있습니다.

Hero위젯에 대해 간단히 알아보겠습니다.

Hero Widget

Hero위젯은 문자열인 tag가 필요하며, 애니메이션이 작동되게 하려면 두 경로에서 동일해야 합니다. 여기서 두 경로는 A->B로 이동할 시 A의 Hero위젯 tag와 B의 Hero위젯 태그가 동일해야 합니다. 이렇게 해주면 한 화면에서 다음 화면으로 이동할 때 Flutter에서 애니메이션 전환을 자동으로 처리해 줍니다.

 

이제 main.dart파일의 빌드 메서드로 들아가서 Row에 아이콘을 표시하도록 하겠습니다.

유저가 이미지를 탭 할 때 경로를 변경하고 싶으므로 GestureDetector사용하고 그 안에 이미지를 포함하고 있습니다. 터치를 감지하고 싶은 Widget의 부모에 GestureDetector를 사용하면 됩니다. GestureDetector의 child에 위에서 만든 Util클래스의 buildHeroIcon 메서드를 불러줍니다.

 

지금까지 코딩을 화면으로 살펴보겠습니다.

아직까지는 위 그림들을 클릭해도 아무런 일도 일어나지 않습니다.

 

이제 사용자가 아이콘 중 하나를 클릭하면 경로를 변경하도록 변경하겠습니다. 세부화면을 포함하는 새 파일을 details.dart파일을 만들었고 아래와 같이 작성하였습니다.

details.dart

Details는 Stateless 위젯으로 위젯이 호출될 때 path와 pag를 설정하는 생성자를 가지고 있습니다. build 메서드에서는 Scaffold를 리턴해 주고 있고 body의 child에서 Util의 buildHeroDestination을 호출하고 있습니다.

buildHeroDestination 메서드는 아래와 같이 작성하였습니다.

메소드에서 Hero위젯을 리턴하고 있으며 buildHeroIcon메서드와의 차이점은 width를 받아 부모 위젯의 가로길이만큼 컨테이너 크기를 갖는다는 점입니다. 여기서 중요한 점은 Hero위젯으로 리턴을 해주고 tag명이 같아야만 A에서 B로 화면 이동을 할 때 플러터가 애니메이션 처리를 해준다는 점입니다. 우리는 위에서 icon도 Hero위젯으로 설정하고 있었으므로 A->B가 화면 모두 Hero위젯에서 Hero위젯으로 화면 전환이 이뤄집니다.

 

마지막으로 main.dart파일의 HeroPage 위젯을 수정하겠습니다.

아이콘을 탭 할 때 화면을 라우팅 처리를 해줄 메소드 chageRoute를 아래와 같이 만들었습니다.

chageRoute 메서드는 매개변수로 context와 tag명(dog)를 받고 있습니다. switch에서 태그명을 찾아 분기한 후, Navigator.push의 builder에서 tag에 맞는 Details위젯을 생성하고 있습니다.

 

이제 아이콘을 택할 때마다 changeRoute메서드를 호출하게 해줘야 합니다.

GestureDetector를 사용했으므로, onTap안에서 chageRoute메서드를 호출하게 할 수 있습니다. 각 아이콘을 탭 할 때 해당하는 그림을 인식하는 tag의 문자열이 전달될 것이고 이 알맞게 라우팅이 될 것입니다.


코딩이 모두 끝났습니다. 완성된 화면을 보도록 하겠습니다.

클릭하면 애니메이션과 함께 화면 전환이 이뤄지는 걸 볼 수 있습니다.


timeDilation 으로 화면 전환 느리게 해 보기

혹시 너무 빠르다고 생각된다면 schedular 패키지의 timeDilation을 이용하여 느리게 할 수 있습니다.

details.dart파일에서 scheduler패키지를 가져오고 있습니다. 여기서 show를 사용하고 있는데 show를 사용하면 패키지 내에서 특정 요소를 선택할 수 있게 됩니다. 즉 schedular의 라이브러리에서 오직 timeDeilation만 액세스 할 수 있습니다.  build메서드에서 timeDilation을 10으로 설정하였습니다. 정상 속도는 1이므로 10으로 설정하면 10배 느리게 표시될 것입니다. 0~1 사이의 값을 설정하면 애니메이션을 더 빠르게 만들 수도 있습니다.

앱에서 보면 아래와 같이 매우 느려진 걸 확인해 볼 수 있습니다.


여기까지 수고하셨습니다.

 

댓글