Я покажу вам 6 прикольных анимационных эффектов, которые можно попробовать в своих приложениях. Добавлять анимацию с Flutter — одно удовольствие. И делать это можно по-разному. Например, можно скачать пакет с dart pub
или воспользоваться виджетом AnimatedBuilder
, который позволяет настроить каждую деталь анимации.
В этой статье я буду работать с виджетом AnimatedBuilder
. Если вы не знакомы с ним, то почитайте документацию. Раз мы решили поработать с AnimatedBuilder
, то нам потребуются два дополнительных виджета:
1. AnimationController
— задает длительность анимации;
2. Animation
— определяет тип и стиль анимации.
Проще говоря, эти виджеты используются для настройки и обработки анимации. Не забудьте протестировать анимацию в виджете изменяемых состояний StatefulWidget
. А в определение класса обязательно добавьте SingleTickerProviderStateMixin
. Он нужен для управления временем в анимации.
Готовы начать? Поехали.
Базовый макет
Я создал базовый макет, на котором вы можете потренироваться в настройке и переключении анимации. Выглядит он вот так:
В процессе работы мы будем пользоваться разными изображениями. Вы можете добавить свои изображения или другие виджеты.
Триггером для анимации у нас служит плавающая кнопка снизу. Я буду активировать анимацию через вызов _controller.forward()
.
Не пугайтесь кода ниже. Пользуйтесь им для настройки контроллера и виджета анимации.
Теперь я познакомлю вас с разными типами анимации в двух блоках кода — для определения и использования анимации. Все очень просто: сначала выбираете понравившийся тип анимации, а затем копируете и вставляете два блока кода. Первый нужен для запуска контроллера, а второй — для работы с анимацией.
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
//*-----определяем Animation и AnimationController-----*
AnimationController _controller;
Animation _myAnimation;
//*-----запускаем Animation и AnimationController-----*
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
//-disposing the animation controller-
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Animations"),
),
body: Center(
child:
Container(
width: 250,
height: 250,
decoration: BoxDecoration(
image: new DecorationImage(
image: new AssetImage(
'assets/images/sample-image.png',
)
)
),
)
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
floatingActionButton:
FloatingActionButton(
child: Icon(Icons.play_arrow),
onPressed: (){
//*------включаем анимацию-----*
_controller.forward();
},
),
);
}
}
01. Появление/исчезновение
Воспользуйтесь кодом ниже для определения анимации. Лучше всего это делать через метод initState
. Теперь он будет запускаться только при отображении StatefulWidget
.
AnimationController _controller;
Animation _myAnimation;
void initState() {
// TODO: implement initState
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1200),
);
_myAnimation = CurvedAnimation(parent: _controller, curve: Curves.easeIn);
}
Во Flutter уже есть встроенный виджет под названием FadeTransition
. Таким образом, мы можем обернуть наш виджет-контейнер в FadeTransition
, а затем настроить динамические значения для непрозрачности.
body: Center(
child:
FadeTransition(
opacity: _myAnimation,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
image: new DecorationImage(
image: new AssetImage(
'assets/images/ghost.png',
)
)
),
),
)
),
02. Изменение размера/пульсация
Это тоже простая разновидность анимации. Для начала, зададим нужные параметры.
AnimationController _controller;
Animation<Size> _myAnimation;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1000),
);
_myAnimation = Tween<Size>(
begin: Size(100, 100),
end: Size(120, 120)
).animate(
CurvedAnimation(parent: _controller, curve: Curves.bounceIn)
);
_controller.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_controller.repeat();
}
});
}
Возможно, сейчас вы заметите что-то новое. Например, мы используем _controller.addStatusListener()
каждый раз, когда хотим повторить анимацию. После определения анимации в AnimationController
она готова к использованию в виджете-контейнере.
body: Center(
child:
AnimatedBuilder(animation: _myAnimation,
builder: (ctx, ch) => Container(
width: _myAnimation.value.width,
height: _myAnimation.value.height,
decoration: BoxDecoration(
image: new DecorationImage(
image: new AssetImage(
'assets/images/heart.png',
)
)
),
)
)
),
03. Скольжение
Slide-анимация — это еще одна встроенная функция Flutter. Вот, как ее можно определить.
AnimationController _controller;
Animation<Offset> _myAnimation;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_myAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.5, 0.0),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.elasticIn,
));
}
Чтобы воспользоваться анимацией, оберните ее в виджет SlideTransition
. Проще простого, не так ли?
body: Center(
child:
SlideTransition(
position: _myAnimation,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: FlutterLogo(size: 150.0),
),
),
),
04. Прыгающая анимация
Еще одна забавная разновидность, которую можно попробовать. Во многом она похожа на анимацию пульсации. Только помните, что в этот раз нам нужно будет изменить отступы контейнера. Давайте определим параметры.
AnimationController _controller;
Animation<double> _slideAnimation;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1000),
);
_slideAnimation = Tween(begin: 200.0, end: 120.0).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.0, 1.0, curve: Curves.elasticIn),
),
)..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_controller.repeat(reverse: true);
}
});
}
Будьте осторожны — мы играем с огнем. Если я выставлю граничное значение 0.0, то появится ошибка. Для тех, кто уже работал с Flutter, это совсем не новость. Да, перед вами — ошибка переполнения, она же — overflow error
. Мы не можем быть уверенными в том, что значения в этих границах будут меняться. Особенно в случае, если эффект анимации (эластичный) выйдет за пределы границ. Запомните, что отступы не могут иметь отрицательного значения.
Теперь, когда мы настроили все необходимые параметры, самое время воспользоваться анимацией.
body:
AnimatedBuilder(animation: _slideAnimation,
builder: (ctx, ch) => Container(
width: 100,
height: 100,
margin: EdgeInsets.only(
top: _slideAnimation.value,
left: 125
),
decoration: BoxDecoration(
image: new DecorationImage(
image: new AssetImage(
'assets/images/bounce-ball.png',
)
)
),
)
),
05. 3D-переворот
Flip-анимация — это простой и прикольный эффект, который легко добавить в приложение. (Одна из моих любимых анимаций). Давайте посмотрим, как все реализовать.
AnimationController _controller;
Animation _myAnimation;
AnimationStatus _animationStatus = AnimationStatus.dismissed;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_myAnimation = Tween(end: 1.0, begin: 0.0).animate(_controller)
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
_animationStatus = status;
});
}
Здесь появляется кое-что новенькое — AnimationStatus
. Им я пользовался для реализации прямых и обратных функций. Этот дополнительный виджет помогает мне получить текущий статус анимации.
Тут я воспользовался простым контейнером, чтобы показать flip-анимацию в действии.
body: Center(
child: Transform(
alignment: FractionalOffset.center,
transform: Matrix4.identity()
..setEntry(3, 2, 0.002)
..rotateX(pi*(_myAnimation.value)),
child: Container(
color: Colors.blueAccent,
width: 200,
height: 200,
child: Icon(
Icons.accessibility_new,
color: Colors.white,
size: 50,
),
),
)
),
06. Вращение с падением
Перейдем к более сложным примерам. Здесь я объединил сразу несколько эффектов. Мы называем это последовательностью анимации. Посмотрите, как можно определить анимацию врещения.
AnimationController _controller;
Animation _rotateAnimation;
Animation<double> _slideAnimation;
Animation<double> _opacityAnimation;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 3000),
);
_rotateAnimation = Tween(end: 0.15, begin: 0.0)
.animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.0, 0.5, curve: Curves.bounceInOut),
),
);
_slideAnimation = Tween(begin: 100.0, end: 600.0).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.5, 1.0, curve: Curves.fastOutSlowIn),
),
);
_opacityAnimation = Tween(begin: 1.0, end: 0.0).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.5, 1.0, curve: Curves.fastOutSlowIn),
),
);
}
Обратите внимание, что при определении анимации мы пользуемся 3 отдельными виджетами Animation
. И для всех них берется один AnimationController
. А еще я передавал разные значения для каждого виджета Interval
. Именно так и задается последовательность анимации.
Теперь давайте посмотрим, как работает последовательность анимации:
body:
AnimatedBuilder(
animation: _slideAnimation,
builder: (ctx, ch) => Container(
width: 200,
height: 100,
padding: EdgeInsets.all(0),
margin: EdgeInsets.only(
left: 75,
top: _slideAnimation.value,
),
child: RotationTransition(
turns: _rotateAnimation,
child: Center(
child: Text('Animation', style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(0, 0, 128, _opacityAnimation.value)
),),
),
),
),
),
Все правильно! Нам нужен еще один виджет –AnimatedBuilder
. Затем мы можем поменять значения контейнера. В этом примере я изменял отступы (для смены положения объекта) и непрозрачность.
Примеры анимации можно посмотреть на Github
Читайте также:
Перевод статьи Sahan Amarsha: Cool Flutter Animations That You Can Try