애니메이션은 일반적으로 앱이나 웹사이트의 시각적 매력을 높이고 사용자의 전반적인 참여를 향상시킵니다. Forrester Research의 연구에 따르면 애니메이션이 잘 구현된 웹사이트는 사용자 참여도가 최대 400% 증가하는 것으로 나타났습니다. 매력적인 애니메이션은 사용자의 관심을 끌고 플랫폼과 더 많이 상호 작용하도록 장려할 수 있습니다. 그러나 특히 고급 애니메이션 도구 및 기술을 사용하여 작업할 때 개발자가 애니메이션을 마스터하기 위한 학습 곡선이 있습니다.
애니메이션 경험이 없는 개발자가 Rive를 파악하는 것은 다른 애니메이션 도구나 프레임워크에 비해 상대적으로 쉬울 수 있습니다. Rive(이전의 Flare)는 애니메이션 경험이 거의 또는 전혀 없는 개발자도 사용자 친화적이고 쉽게 접근할 수 있도록 설계되었습니다. 이 기사에서는 간단하고 멋진 Rive 애니메이션을 쉽게 만들고 Flutter 앱에서 관리하는 방법을 알아봅니다.
Rive 소개🧙♂️
간단한 대화형 로그인 애니메이션🚀
결론🏋️♀️
참고자료🧶
Rive는 개발자와 디자이너가 모바일 앱, 웹 애플리케이션, 게임을 포함한 다양한 플랫폼을 위한 멋진 대화형 애니메이션을 만들 수 있도록 지원하는 강력 하고 사용자 친화적인 애니메이션 도구이자 런타임 엔진입니다.
주요 개념은 다음과 같습니다.
간단한 로그인 애니메이션을 만들고 이를 Flutter 앱으로 내보내는 과정을 살펴보겠습니다. StateMachine을 사용하여 앱에서 이 애니메이션의 상호 작용을 관리하겠습니다. 결국 이런 모습이 되겠죠 👇👇
Rive 아트보드에서 요소를 설정하려면 아래 단계를 따르세요.
다음으로 뼈를 묶고 무게를 달아보겠습니다. 바인딩을 사용하면 뼈대가 움직일 때 캐릭터 표면의 해당 부분도 그에 따라 움직여서 변형된 듯한 느낌을 줍니다. 정점 가중치라고도 알려진 가중치에는 특정 뼈대와의 근접성을 기준으로 캐릭터 메시의 각 정점에 영향 값(가중치)을 할당하는 작업이 포함됩니다. 바인딩할 모양의 경로로 이동하겠습니다. 목의 경우, 목뼈에 묶는 방법입니다.
뼈대를 바인딩한 후 정점에 가중치를 할당하여 정점을 설정합니다. 여기서는 두 개의 뼈대가 50%의 영향을 미치도록 하기 위해 마지막 정점 세트를 50%로 설정했습니다. 특히 설정된 정점이 두 뼈대에 영향을 미치는 섹션을 덮는 경우에는 50%를 사용해야 합니다. 이제 머리카락 경로에도 동일한 작업을 수행합니다. 또한 왼쪽 및 오른쪽 뼈를 하나의 뼈에서 두 개의 뼈로 변경하여 머리카락에 원하는 흐르는 듯한 움직임을 얻을 수 있습니다.
이 애니메이션에는 깜박임 효과를 적용하고 싶습니다. 이를 달성하기 위해 다음과 같이 두 눈 모양에 클립 기능을 사용하겠습니다 👇👇
다음으로 애니메이션 중에 머리를 이동하려고 하므로 변환 제약 조건을 사용하여 이 요소에 머리 추적을 추가하겠습니다. 2D 요소이므로 변환 제약 조건을 추가하면 깊이와 일종의 3D 효과가 제공됩니다. 모든 것을 선택하고 그룹화하십시오. 이제 단일 그룹이 생겼습니다.
그런 다음 왼쪽 상단에서 그룹 도구를 선택하고 머리 중앙(코 부분)에 그룹을 만듭니다. 오른쪽 도구 모음에서 스타일을 그룹에서 대상으로 변경하고 이름을 ctrl_front로 변경하고 복제한 다음 복제 이름을 ctrl_back으로 지정합니다.
대상 ctrl_back 의 경우 오른쪽 도구 모음에서 제약 조건 옵션을 선택합니다. 사용 가능한 제약 옵션 목록에서 변환 제약 조건을 선택하세요. 해당 속성을 설정하려면 선택한 제약 옵션 앞에 있는 아이콘을 클릭하세요.
강도를 -100으로 설정하고 대상을 Ctrl Front로 설정합니다. 이제 Ctrl 키를 앞으로 움직이면 Ctrl 키가 반대 방향으로 움직입니다. 귀처럼 반대 방향으로 움직여야 하는 얼굴 부분에 대한 제약 조건을 설정하는 데 도움이 됩니다. 이렇게 보여야 합니다 👇👇
이제 얼굴의 나머지 부분에 대한 제약 조건을 설정하겠습니다. 또한 눈(왼쪽 및 오른쪽)과 귀(왼쪽 및 오른쪽)를 그룹화하여 더 잘 관리할 수 있도록 도와드리겠습니다. 눈에 대한 제약 조건을 이렇게 설정하겠습니다 👇👇
그룹 | 구속 강도 | 원점 위치 | 표적 |
---|---|---|---|
안경 | 5% | ctrl_front 원점과 동일 | ctrl_front |
눈썹 | 10% | ctrl_front 원점과 동일 | ctrl_front |
귀 | 5% | 원산지를 설정할 필요가 없습니다 | ctrl_back |
코 | 5% | ctrl_front 원점과 동일 | ctrl_front |
얼굴 | 5% | ctrl_front 원점과 동일 | ctrl_front |
입술에는 제약 조건을 설정할 필요가 없습니다.
모든 제약 조건을 추가한 후의 모습입니다 👇👇
💃🏻 🥳 축하합니다. 우리가 달성하고자 하는 종류의 애니메이션에 맞게 요소를 성공적으로 준비했습니다. 아휴!!
오른쪽 도구 모음에서 애니메이션 버튼을 클릭하여 애니메이션 인터페이스로 전환합니다. 6개의 애니메이션 타임라인을 생성하고 모든 것을 상태 머신에 연결하겠습니다. 타임라인에서는 이전에 뼈대와 제약 조건을 설정한 내용을 사용하여 키프레임을 설정하여 달성하려는 애니메이션을 만들 수 있습니다.
첫 번째 타임라인 애니메이션은 유휴 애니메이션입니다. 애니메이션의 유휴 상태가 됩니다. 애니메이션 요소가 작동하지 않을 때 이를 사용합니다.
이 유휴 애니메이션에서는 호흡, 약간의 머리카락 움직임, 깜박임 등의 환상을 만들어 보겠습니다. 목뼈, 머리카락 뼈, 오른쪽/왼쪽 눈 요소를 사용하여 다양한 포즈에 필요한 키프레임을 설정합니다. 즉, 타임라인의 지점에서 선택한 항목의 특정 속성을 설정할 수 있습니다. 한 키프레임에서 다음 키프레임으로의 전환 스타일을 고려하여 필요한 보간 유형을 선택합니다. 타임라인 섹션 오른쪽 하단에서 찾을 수 있습니다. 보간은 한 키프레임에서 다음 키프레임으로 이동하려는 방식에 따라 고정, 선형 또는 곡선 중 하나입니다. 이런 모습이겠죠 👇👇
위의 gif에서 타임라인의 다양한 키프레임에서 선택한 항목에 대해 다양한 포즈를 설정했음을 알 수 있습니다. 한 키프레임에서 다른 키프레임으로의 전환이 애니메이션을 형성합니다. 동일한 절차를 사용하여 다른 5개의 타임라인을 생성합니다. 여기를 클릭하면 이 애니메이션을 보고 다양한 타임라인을 자세히 확인할 수 있습니다. 이렇게 생겼네요 👇👇
우리는 이 애니메이션 프로세스의 마지막 부분에 이르렀습니다. 상태 머신은 애니메이션을 연결하는 시각적인 방법입니다. 상태 머신을 사용하면 설정한 입력에 따라 재생되는 애니메이션을 제어할 수 있습니다. 두 개 이상의 타임라인 애니메이션을 혼합하거나 혼합하여 동시에 재생할 수 있습니다. 상태 머신에서 올바른 종류의 입력을 선택해야 합니다. 이것이 앱에서 애니메이션을 제어하는 데 사용되는 입력이기 때문입니다.
상태 머신에는 세 가지 종류의 입력이 있습니다.
애니메이션 패널에서 더하기 버튼을 클릭하고 상태 머신을 만듭니다. 이름을 Login State Machine 으로 지정하겠습니다. 이 이름은 나중에 코드에서 상태 머신을 식별하는 데 필요하기 때문에 중요합니다.
상태 머신을 설정하려면 아래 단계를 따르세요.
이제 상태 머신의 전체 애니메이션은 다음과 같습니다 👇👇
여기에서 전체 애니메이션과 상태 머신을 확인하세요.
축하합니다 🥳, 요소에 성공적으로 애니메이션을 적용하고 상태 머신으로 설정했습니다! 하지만 리브 파일을 내보내기 전에 배경과 캐릭터의 셔츠 색상을 변경하겠습니다. 이런 모습이겠죠👇🏻
배경색은 (#B581EB), 캐릭터 셔츠색상은 (#BD08D7) 입니다.
모든 내용을 자세히 볼 수 있는 애니메이션 링크는 다음과 같습니다.
로그인 페이지에서 이 애니메이션을 사용하겠습니다. Flutter 앱 프로젝트를 생성하고 pubspec.yaml
에 Rive 종속성을 추가합니다.
dependencies: rive: ^0.11.12
또한 내보낸 Rive 파일을 프로젝트 자산에 추가하세요. 이제 디자인을 기반으로 UI를 만들 수 있습니다. 우리는 애니메이션이 다음을 수행하도록 하는 것을 목표로 합니다:
먼저 Widget Build 기능에 앞서 몇 가지 사항을 정의하겠습니다.
///Login details String emailCred = "[email protected]"; String passwordCred = "123456"; /// input form controller FocusNode emailFocusNode = FocusNode(); TextEditingController emailCtr = TextEditingController(); FocusNode passwordFocusNode = FocusNode(); TextEditingController passwordCtr = TextEditingController(); /// rive controller and input values StateMachineController? controller; SMIInput<bool>? check; SMIInput<double>? look; SMIInput<bool>? success; SMIInput<bool>? fail; bool isLoading = false; bool isError = false; @override void initState() { emailFocusNode.addListener(emailFocus); passwordFocusNode.addListener(passwordFocus); super.initState(); } @override void dispose() { emailFocusNode.removeListener(emailFocus); passwordFocusNode.removeListener(passwordFocus); super.dispose(); } void emailFocus() { check?.change(emailFocusNode.hasFocus); } void passwordFocus() { check?.change(passwordFocusNode.hasFocus); }
여기서 우리는 다음 사항에 주목할 수 있습니다.
emailFocus
및 passwordFocus
함수에서 check 입력은 부울 FocusNode.hasFocus
기반으로 변경됩니다.initState
및 dispose
함수에서 리스너가 추가 및 제거되는 것을 볼 수 있습니다. 청취자는 초점 변경을 듣는 데 사용됩니다.
여기에서 UI 코드와 나머지 코드를 확인할 수 있습니다. 이 코드 조각은 RiveAsset을 추가하는 방법을 보여줍니다.
SizedBox( height: 250, width: 250, child: RiveAnimation.asset( "assets/login_screen.riv", fit: BoxFit.fitHeight, stateMachines: const ["Login State Machine"], onInit: (artboard) { controller = StateMachineController.fromArtboard( artboard, "Login State Machine", ); if (controller == null) return; artboard.addController(controller!); check = controller?.findInput("check"); look = controller?.findInput("look"); success = controller?.findInput("success"); fail = controller?.findInput("fail"); }, ), ),
위의 코드에서 다음 사항을 확인할 수 있습니다.
로그인 기능에 대한 코드는 다음과 같습니다.
void login()async{ //extract the text coming from the text fields final email = emailCtr.text; final password = passwordCtr.text; //Set loading boolean to true and delay to give an illusion of loading setState(() { isLoading = true; }); await Future.delayed( const Duration(milliseconds: 2000), ); // check if details entered is the same as the correct creditials defined if (email == emailCred && password == passwordCred) { //if correct trigger the success input and set error boolean to false success?.change(true); setState(() { isError = false; }); if(context.mounted){ // delay and navigate to home screen await Future.delayed( const Duration(seconds: 2),(){ Navigator.push(context, MaterialPageRoute(builder: (context) =>const HomeScreen())); }); } } else { // if details don't match defined credentials // set error boolean to true and trigger the fail input // set loading boolean to false setState(() { isError = true; }); fail?.change(true); } setState(() { isLoading = false; }); }
여기에서 전체 코드를 확인하세요.
이를 통해 로그인 애니메이션 코드가 완성되었습니다. 모든 것이 어떻게 보이는지는 다음과 같습니다.
축하해요! 간단한 대화형 로그인 애니메이션을 완성했습니다. 다음은 우리가 달성할 수 있었던 모든 것에 대한 개요입니다.
이 튜토리얼을 단계별로 따라하면 몇 가지 병목 현상이 발생할 수 있지만 연습하면 더 쉬워질 것입니다. 이 튜토리얼을 진행하는 동안 도움이 필요하면 Twitter 로 저에게 연락하거나 댓글을 달 수 있습니다.
Rive 애니메이션을 더 잘 이해하려면 다음 비디오 튜토리얼을 확인하세요.
Rive 애니메이션에 대한 여러 비디오 튜토리얼을 Rive 채널에서 확인할 수도 있습니다.
여기에도 게시되었습니다.