개발노트

69. [Flutter] RIVE 사용하기 (움직이는 애니메이션 패키지) 본문

앱 개발/Flutter

69. [Flutter] RIVE 사용하기 (움직이는 애니메이션 패키지)

mroh1226 2024. 2. 20. 16:03
반응형

RIVE

RIVE는 Lottie 와 비슷한 패키지로, 움직이는 애니메이션을 제공합니다.

특정 행동에서의 애니메이션 혹은, Input의 값을 변환켜 한가지가 아닌 여러가지 동작을 할 수 있게 만들어줍니다.

즉, RIVE의 가장 큰 특징은 사용자의 조작에 따라 상호작용이 가능한 애니메이션을 구현할 수 있습니다.

 


구현 목표.

RIVE 에 있는 정답곰(정답, 오답에 반응하는 곰) 을 버튼 클릭으로 움직이게 만들어봅니다.

  • 정답 곰은 StateInput을 2개(Correct, Incorrect) 가지고 있으며, 2가지 Input 을 전달하는 버튼을 각각 구현합니다.
  • State 가 변했을 때 SnackBarstateMachineName stateName이 표시되도록 구현합니다.

구현된 정답곰


1. Flutter 프로젝트에 RIVE 패키지를 설치합니다.

- RIVE 패키지설치 링크: https://pub.dev/packages/rive/install

 

rive install | Flutter package

Rive 2 Flutter Runtime. This package provides runtime functionality for playing back and interacting with animations built with the Rive editor available at https://rive.app.

pub.dev

 

2. RIVE  사이트 에서 마음에 드는 애니메이션 파일을 다운 받습니다.

- RIVE 공식 사이트 Community: https://rive.app/community/

*예제로 사용할 RIVE 파일 (정답, 오답에 리액션하는 북극곰) :https://rive.app/community/595-1139-bear-avatar-remix/

 

Bear Avatar Remix

You might recognise this cute guy from one of the most popular language learning apps! I wanted to remix the bear character from Duolingo in Rive. This example uses Bind #Bones for the vector deformations in the scarf and head. The #Statemachine allows you

rive.app

 

(다운로드 받는 방법 설명)

2-1) 마음에 드는 RIVE 애니케이션을 클릭 > Remix 클릭 > Start editing 클릭

Rimex > Start editing 클릭

 

2-2) 자동으로 RIVE Editing 화면으로 이동되며, 여기서 필요한 Editing을 작업해줍니다.
(저 같은 경우에는 Incorrect 일 때 배경색을 더 붉은색으로 바꿔줬습니다.)

RIVE Editing 화면

 

2-3) 상단 탭바에서 Export 아이콘 클릭 > Download 클릭 > For runtime .riv 클릭 > 다운로드 완료!

RIVE Editing 완료 후, 다운로드 하기

 

 

3. 다운로드 받은 riv 파일을 Flutter 프로젝트 내부 폴더에 넣어주고, (새로 생성하여 assets/animations 에 넣어줬음) pubspec.yaml 에 아래와 같이 assets: 에 경로를 추가해줍니다.

다운받은 riv 파일을 Flutter 프로젝트 폴더에 넣어주고, pubspec.yaml의 assets: 에 경로지정

 

 


예제 소스.

import 'package:flutter/material.dart';
import 'package:rive/rive.dart';

class RiveScreen extends StatefulWidget {
  const RiveScreen({super.key});

  @override
  State<RiveScreen> createState() => _RiveScreenState();
}

class _RiveScreenState extends State<RiveScreen> {
  late final StateMachineController _stateMachineController;

//아트보드 초기화 메소드(RIVE 애니메이션이 그려지는 보드)
  void _onInit(Artboard artboard) {
    _stateMachineController = StateMachineController.fromArtboard(
      artboard,
      "State Machine 1",
      onStateChange: (stateMachineName, stateName) {
        //State가 바뀔 때 값을 가져옴
        //stateMachineName:State Machine 1
        //stateName: Correct, Incorrect, Idle
        final snackBar = SnackBar(
            content: Text(
          '$stateMachineName / $stateName',
          style: const TextStyle(fontSize: 28, color: Colors.yellow),
        ));
        ScaffoldMessenger.of(context).showSnackBar(snackBar);
      },
    )!;
    artboard.addController(_stateMachineController);
  }

//Correct 버튼을 클릭했을 때 메소드 
  void _onTapCorrect() {
    //state Machine 으로 부터 "Correct" Input을 가져옴(bool형)
    final input = _stateMachineController.findInput<bool>("Correct")!;
    //input이 true로 바뀌었다고 알려줌
    input.change(true);
  }

//InCorrect 버튼을 클릭했을 때 메소드
  void _onTapIncorrect() {
  	//state Machine 으로 부터 "InCorrect" Input을 가져옴(bool형)
    final input = _stateMachineController.findInput<bool>("Incorrect")!;
    //input이 true로 바뀌었다고 알려줌
    input.change(true);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            SizedBox(
              height: 400,
              width: 500,
              //https://rive.app/community/595-1139-bear-avatar-remix/
              child: RiveAnimation.asset(	//
                "assets/animations/reaction_bear.riv",	//경로 입력
                fit: BoxFit.cover,
                artboard: "New Artboard",	//Artboard 이름 입력
                stateMachines: const ["State Machine 1"],	//State Machine명 입력
                onInit: _onInit,	//아트보드(Artboard) 초기화 소스 입력
              ),
            ),
            ElevatedButton(
              onPressed: _onTapCorrect,
              child: const Text("Correct Answer"),
            ),
            ElevatedButton(
                onPressed: _onTapIncorrect,
                child: const Text("Incorrect Answer"))
          ],
        ),
      ),
    );
  }
}

소스 설명.

*RIVE의 간단 개념

  • Artboard: Animation이 그려지는 곳
  • State Machine: Animation State 동작 로직을 담당
  • Inputs: State를 변화 시킬 수 있는 입력값
RIVE 파일, Artboard, State Machine 매핑하기

Flutter와 RIVE Editing 간의 매핑

RiveAnimation 위젯

  • RiveAnimation.asset("assets/animations/reaction_bear.riv") 로 경로에 있는 Rive 파일(.riv)을 불러옵니다.
  • artboard: 속성에 RIVE Editing 에 작성된 아트보드 명을 입력합니다.
  • stateMachines: 속성에 Animation State Machine 명을 입력합니다.
  • onInit: 아트보드 초기화 메소드나 로직을 입력해줍니다.

*하단에 ElevatedButton 2개에 각각 Correct, Incorrect Input을 전달할 수 있는 버튼을 만들어줍니다.

 

StateMachineController, Artboard 초기화 / Input 값 변화로 애니메이션 동작하기

Flutter와 RIVE Editing 간의 매핑

 

_onInit(Artboard artboard) 메소드

  • onInit: 속성에 입력해주었던 _onInit 메소드는 StateMachineController를  초기화 합니다.
  • StateMachineController.fromArtboard() 에 전달받은 artboardState Machine명을 입력합니다.
  • artboard.addController(StateMachineController) 로 아트보드에 컨트롤러를 연결해줍니다.
  • onStateCahnge: 속성으로 state가 변할 때마다 stateMachineNamestateName을 받아올 수 있습니다.
    SnackBar를 통해 이를 확인 할 수 있도록 만들어줍니다.

_onTapCorrect(), _onTapIncorrect() 메소드

  • StateMachineController 에게 input 값(Correct, Incorrect)이 true로 변한 것을 알리는 메소드입니다.
  • stateMachineController.findInput<bool>("input명") 으로 해당 Input을 가져옵니다.
  • input.change(true) 로 input값에 true를 넣어 RIVE 애니메이션이 동작하게 됩니다.
반응형
Comments