Flutter-애니메이션
애니메이션은 모든 모바일 애플리케이션에서 복잡한 절차입니다. 복잡성에도 불구하고 Animation은 사용자 경험을 새로운 수준으로 향상시키고 풍부한 사용자 상호 작용을 제공합니다. 풍부함으로 인해 애니메이션은 현대 모바일 애플리케이션의 필수적인 부분이되었습니다. Flutter 프레임 워크는 애니메이션의 중요성을 인식하고 모든 유형의 애니메이션을 개발할 수있는 간단하고 직관적 인 프레임 워크를 제공합니다.
소개
애니메이션은 움직임의 환상을주기 위해 특정 시간 내에 특정 순서로 일련의 이미지 / 그림을 보여주는 과정입니다. 애니메이션의 가장 중요한 측면은 다음과 같습니다.
애니메이션에는 시작 값과 끝 값의 두 가지 고유 한 값이 있습니다. 애니메이션은 시작 값 에서 시작 하여 일련의 중간 값을 거쳐 마지막으로 끝 값에서 끝납니다. 예를 들어 페이드 어웨이 위젯에 애니메이션을 적용하려면 초기 값은 전체 불투명도가되고 최종 값은 0이됩니다.
중간 값은 본질적으로 선형 또는 비선형 (곡선) 일 수 있으며 구성 할 수 있습니다. 애니메이션이 구성된대로 작동하는지 이해합니다. 각 구성은 애니메이션에 다른 느낌을 제공합니다. 예를 들어, 위젯 페이딩은 본질적으로 선형이되는 반면 공의 튀는 것은 본질적으로 비선형입니다.
애니메이션 프로세스의 지속 시간은 애니메이션의 속도 (느림 또는 빠름)에 영향을줍니다.
애니메이션 시작, 애니메이션 중지, 애니메이션 반복 횟수 설정, 애니메이션 프로세스 반전 등과 같은 애니메이션 프로세스를 제어하는 기능,
Flutter에서 애니메이션 시스템은 실제 애니메이션을 수행하지 않습니다. 대신 모든 프레임에서 이미지를 렌더링하는 데 필요한 값만 제공합니다.
애니메이션 기반 클래스
Flutter 애니메이션 시스템은 Animation 객체를 기반으로합니다. 핵심 애니메이션 클래스와 그 사용법은 다음과 같습니다.
생기
특정 기간 동안 두 숫자 사이에 보간 된 값을 생성합니다. 가장 일반적인 애니메이션 클래스는 다음과 같습니다.
Animation<double> − 두 십진수 사이의 값 보간
Animation<Color> − 두 색상 사이의 색상 보간
Animation<Size> − 두 크기 사이의 크기 보간
AnimationController− 애니메이션 자체를 제어하는 특수 애니메이션 개체. 응용 프로그램이 새 프레임을 준비 할 때마다 새 값을 생성합니다. 선형 기반 애니메이션을 지원하며 값은 0.0에서 1.0까지 시작합니다.
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);
여기서 컨트롤러는 애니메이션을 제어하고 기간 옵션은 애니메이션 프로세스의 기간을 제어합니다. vsync는 애니메이션에 사용되는 리소스를 최적화하는 데 사용되는 특수 옵션입니다.
CurvedAnimation
AnimationController와 유사하지만 비선형 애니메이션을 지원합니다. CurvedAnimation은 아래와 같이 Animation 객체와 함께 사용할 수 있습니다.
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)
트윈 <T>
Animatable <T>에서 파생되며 0과 1이 아닌 두 숫자 사이의 숫자를 생성하는 데 사용됩니다. animate 메서드를 사용하고 실제 Animation 개체를 전달하여 Animation 개체와 함께 사용할 수 있습니다.
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this); Animation<int> customTween = IntTween(
begin: 0, end: 255).animate(controller);
Tween은 다음과 같이 CurvedAnimation과 함께 사용할 수도 있습니다.
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);
Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve);
여기서 컨트롤러는 실제 애니메이션 컨트롤러입니다. curve는 비선형 성 유형을 제공하고 customTween은 0에서 255까지의 사용자 정의 범위를 제공합니다.
Flutter 애니메이션의 작업 흐름
애니메이션의 작업 흐름은 다음과 같습니다.
StatefulWidget의 initState에서 애니메이션 컨트롤러를 정의하고 시작합니다.
AnimationController(duration: const Duration(seconds: 2), vsync: this);
animation = Tween<double>(begin: 0, end: 300).animate(controller);
controller.forward();
애니메이션 기반 리스너, addListener를 추가하여 위젯의 상태를 변경합니다.
animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
setState(() {
// The state that has changed here is the animation object’s value.
});
});
빌드 인 위젯, AnimatedWidget 및 AnimatedBuilder를 사용하여이 프로세스를 건너 뛸 수 있습니다. 두 위젯 모두 애니메이션 개체를 받아들이고 애니메이션에 필요한 현재 값을 가져옵니다.
위젯의 빌드 프로세스 중에 애니메이션 값을 가져온 다음 원래 값 대신 너비, 높이 또는 관련 속성에 적용합니다.
child: Container(
height: animation.value,
width: animation.value,
child: <Widget>,
)
작업 응용
Flutter 프레임 워크의 애니메이션 개념을 이해하기 위해 간단한 애니메이션 기반 애플리케이션을 작성해 보겠습니다.
Android 스튜디오 product_animation_app에서 새 Flutter 애플리케이션을 만듭니다 .
product_nav_app에서 product_animation_app으로 자산 폴더를 복사하고 pubspec.yaml 파일 내에 자산을 추가하십시오.
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
기본 시작 코드 (main.dart)를 제거합니다.
가져 오기 및 기본 주요 기능을 추가합니다.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
StatefulWidgtet에서 파생 된 MyApp 위젯을 만듭니다.
class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
}
_MyAppState 위젯을 생성하고 기본 빌드 방법 외에 initState를 구현하고 폐기합니다.
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
@override void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(seconds: 10), vsync: this
);
animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller);
controller.forward();
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
controller.forward();
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue,),
home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
여기,
initState 메서드에서는 애니메이션 컨트롤러 개체 (controller), 애니메이션 개체 (animation)를 만들고 controller.forward를 사용하여 애니메이션을 시작했습니다.
dispose 메서드에서는 애니메이션 컨트롤러 개체 (controller)를 삭제했습니다.
빌드 메소드에서 생성자를 통해 MyHomePage 위젯으로 애니메이션을 보냅니다. 이제 MyHomePage 위젯은 애니메이션 개체를 사용하여 콘텐츠에 애니메이션을 적용 할 수 있습니다.
이제 ProductBox 위젯 추가
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.name, this.description, this.price, this.image})
: super(key: key);
final String name;
final String description;
final int price;
final String image;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(this.name, style:
TextStyle(fontWeight: FontWeight.bold)),
Text(this.description),
Text("Price: " + this.price.toString()),
],
)
)
)
]
)
)
);
}
}
불투명도를 사용하여 간단한 페이드 애니메이션을 수행하는 새 위젯 MyAnimatedWidget을 만듭니다.
class MyAnimatedWidget extends StatelessWidget {
MyAnimatedWidget({this.child, this.animation});
final Widget child;
final Animation<double> animation;
Widget build(BuildContext context) => Center(
child: AnimatedBuilder(
animation: animation,
builder: (context, child) => Container(
child: Opacity(opacity: animation.value, child: child),
),
child: child),
);
}
여기에서는 AniatedBuilder를 사용하여 애니메이션을 수행했습니다. AnimatedBuilder는 애니메이션을 수행하는 동시에 콘텐츠를 빌드하는 위젯입니다. 현재 애니메이션 값을 얻기 위해 애니메이션 개체를받습니다. 애니메이션 값인 animation.value를 사용하여 자식 위젯의 불투명도를 설정했습니다. 실제로 위젯은 불투명도 개념을 사용하여 하위 위젯에 애니메이션을 적용합니다.
마지막으로 MyHomePage 위젯을 만들고 애니메이션 개체를 사용하여 해당 콘텐츠에 애니메이션을 적용합니다.
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title, this.animation}) : super(key: key);
final String title;
final Animation<double>
animation;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
FadeTransition(
child: ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
), opacity: animation
),
MyAnimatedWidget(child: ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"
), animation: animation),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"
),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for meeting",
price: 1500,
image: "tablet.png"
),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"
),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage medium",
price: 20,
image: "floppy.png"
),
],
)
);
}
}
여기에서는 FadeAnimation 및 MyAnimationWidget을 사용하여 목록의 처음 두 항목에 애니메이션을 적용했습니다. FadeAnimation은 불투명도 개념을 사용하여 자식을 애니메이션하는 데 사용되는 빌트인 애니메이션 클래스입니다.
완전한 코드는 다음과 같습니다.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(seconds: 10), vsync: this);
animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller);
controller.forward();
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
controller.forward();
return MaterialApp(
title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,),
home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title, this.animation}): super(key: key);
final String title;
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Listing")),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0),
children: <Widget>[
FadeTransition(
child: ProductBox(
name: "iPhone",
description: "iPhone is the stylist phone ever",
price: 1000,
image: "iphone.png"
),
opacity: animation
),
MyAnimatedWidget(
child: ProductBox(
name: "Pixel",
description: "Pixel is the most featureful phone ever",
price: 800,
image: "pixel.png"
),
animation: animation
),
ProductBox(
name: "Laptop",
description: "Laptop is most productive development tool",
price: 2000,
image: "laptop.png"
),
ProductBox(
name: "Tablet",
description: "Tablet is the most useful device ever for meeting",
price: 1500,
image: "tablet.png"
),
ProductBox(
name: "Pendrive",
description: "Pendrive is useful storage medium",
price: 100,
image: "pendrive.png"
),
ProductBox(
name: "Floppy Drive",
description: "Floppy drive is useful rescue storage medium",
price: 20,
image: "floppy.png"
),
],
)
);
}
}
class ProductBox extends StatelessWidget {
ProductBox({Key key, this.name, this.description, this.price, this.image}) :
super(key: key);
final String name;
final String description;
final int price;
final String image;
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(2),
height: 140,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset("assets/appimages/" + image),
Expanded(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
this.name, style: TextStyle(
fontWeight: FontWeight.bold
)
),
Text(this.description), Text(
"Price: " + this.price.toString()
),
],
)
)
)
]
)
)
);
}
}
class MyAnimatedWidget extends StatelessWidget {
MyAnimatedWidget({this.child, this.animation});
final Widget child;
final Animation<double> animation;
Widget build(BuildContext context) => Center(
child: AnimatedBuilder(
animation: animation,
builder: (context, child) => Container(
child: Opacity(opacity: animation.value, child: child),
),
child: child
),
);
}
결과를 보려면 애플리케이션을 컴파일하고 실행하십시오. 응용 프로그램의 초기 및 최종 버전은 다음과 같습니다.