предисловие
Суть анимации заключается в непрерывном изменении содержимого, отображаемого на экране в течение определенного периода времени, что приводит кпостоянство зренияФеномен.
Анимации обычно можно разделить на две категории:
"промежуточная анимация": Tween-анимация — это разновидность анимации, которая заранее определяет начальную и конечную точки движения объекта, метод движения объекта, время движения, временную кривую, а затем осуществляет переход от начальной точки к конечной точке.
"Анимация на основе физики": Анимация на основе физики — это анимация, которая имитирует реальное движение путем создания модели движения. Например, когда баскетбольный мяч 🏀 падает с высоты, необходимо создать модель движения в соответствии с высотой его падения, гравитационным ускорением, силой отскока от земли и другими влияющими факторами.
Анимация во флаттере
Во Flutter есть много типов анимации, начиная с простого примера, используяAnimatedContainer
управления, затем установите продолжительность анимацииduration
, наконец звонитsetState
Метод изменяет значение свойства, которое необходимо изменить, и создается анимация.
код показывает, как показано ниже
import 'package:flutter/material.dart';
class AnimatedContainerPage extends StatefulWidget {
@override
_AnimatedContainerPageState createState() => _AnimatedContainerPageState();
}
class _AnimatedContainerPageState extends State<AnimatedContainerPage> {
// 初始的属性值
double size = 100;
double raidus = 25;
Color color = Colors.yellow;
void _animate() {
// 改变属性值
setState(() {
size = size == 100 ? 200 : 100;
raidus = raidus == 25 ? 100 : 25;
color = color == Colors.yellow ? Colors.greenAccent : Colors.yellow;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Animated Container')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 在 AnimatedContainer 上应用属性值
AnimatedContainer(
width: size,
height: size,
curve: Curves.easeIn,
padding: const EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(raidus),
),
duration: Duration(seconds: 1),
child: FlutterLogo(),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _animate,
child: Icon(Icons.refresh),
),
);
}
}
Это имплицитная анимация, помимо явной анимации, Хрео-анимация, чересстрочная анимация.
Основные понятия
Флаттер-анимация построена на следующих концепциях.
Animation
Система анимации на основе флаттераAnimation
Объект, представляющий собой абстрактный класс, который содержит значение и состояние текущей анимации (запуск, пауза, перемотка вперед, перемотка назад), но не записывает то, что отображается на экране. Элементы пользовательского интерфейса считываютсяAnimation
Значение объекта и прослушивание изменений состояния для запускаbuild
функция, а затем отображается на экране для создания эффекта анимации.
ОдинAnimation
Объекты продолжают генерировать значения между двумя значениями в течение определенного периода времени, более распространенными типами являютсяAnimation<double>
,Удалитьdouble
В дополнение к типуAnimation<Color>
илиAnimation<Size>
Ждать.
abstract class Animation<T> extends Listenable implements ValueListenable<T> {
/// ...
}
AnimationController
с методом управленияAnimation
Объект, используемый для управления запуском, паузой, окончанием анимации, установкой времени выполнения анимации и т. д.
class AnimationController extends Animation<double>
with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
/// ...
}
AnimationController controller = AnimationController(
vsync: this,
duration: Duration(seconds: 10),
);
Tween
Используется для генерации значений анимации разных типов и диапазонов.
class Tween<T extends dynamic> extends Animatable<T> {
Tween({ this.begin, this.end });
/// ...
}
// double 类型
Tween<double> tween = Tween<double>(begin: -200, end: 200);
// color 类型
ColorTween colorTween = ColorTween(begin: Colors.blue, end: Colors.yellow);
// border radius 类型
BorderRadiusTween radiusTween = BorderRadiusTween(
begin: BorderRadius.circular(0.0),
end: BorderRadius.circular(150.0),
);
Curve
Процесс анимации Flutter по умолчанию является единым, используйтеCurvedAnimation
Кривая времени может быть определена как нелинейная кривая.
class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<double> {
/// ...
}
Animation animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
Ticker
Ticker
Функция обратного вызова, используемая для добавления каждого обновления экранаTickerCallback
, который называется каждым обновлением экрана. похоже на вебrequestAnimationFrame
метод.
class Ticker {
/// ...
}
Ticker ticker = Ticker(callback);
Неявная анимация
Неявные анимации создаются с помощью встроенных виджетов анимации фреймворка Flutter и запускаются путем установки начального и конечного значений анимации. когда используешьsetState
Когда метод изменяет значение свойства анимации виджета, платформа автоматически вычисляет анимацию, которая переходит от старого значения к новому значению.
НапримерAnimatedOpacity
компонент, изменяя егоopacity
Значение может запускать анимацию.
import 'package:flutter/material.dart';
class OpacityChangePage extends StatefulWidget {
@override
_OpacityChangePageState createState() => _OpacityChangePageState();
}
class _OpacityChangePageState extends State<OpacityChangePage> {
double _opacity = 1.0;
// 改变目标值
void _toggle() {
_opacity = _opacity > 0 ? 0.0 : 1.0;
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('隐式动画')),
body: Center(
child: AnimatedOpacity(
// 传入目标值
opacity: _opacity,
duration: Duration(seconds: 1),
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _toggle,
child: Icon(Icons.play_arrow),
),
);
}
}
КромеAnimatedOpacity
Кроме того, есть другие встроенные виджеты неявной анимации, такие как:AnimatedContainer
, AnimatedPadding
, AnimatedPositioned
, AnimatedSwitcher
,AnimatedAlign
Ждать.
явная анимация
Явная анимация относится к анимации, для которой требуется ручная настройка времени анимации, кривой движения и диапазона значений. Передайте значения виджетам анимации, например:RotationTransition
, и, наконец, используйтеAnimationController
Управляет началом и концом анимации.
import 'dart:math';
import 'package:flutter/material.dart';
class RotationAinmationPage extends StatefulWidget {
@override
_RotationAinmationPageState createState() => _RotationAinmationPageState();
}
class _RotationAinmationPageState extends State<RotationAinmationPage>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _turns;
bool _playing = false;
// 控制动画运行状态
void _toggle() {
if (_playing) {
_playing = false;
_controller.stop();
} else {
_controller.forward()..whenComplete(() => _controller.reverse());
_playing = true;
}
setState(() {});
}
@override
void initState() {
super.initState();
// 初始化动画控制器,设置动画时间
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 10),
);
// 设置动画取值范围和时间曲线
_turns = Tween(begin: 0.0, end: pi * 2).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeIn),
);
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('显示动画')),
body: Center(
child: RotationTransition(
// 传入动画值
turns: _turns,
child: Container(
width: 200,
height: 200,
child: Image.asset(
'assets/images/fan.png',
fit: BoxFit.cover,
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _toggle,
child: Icon(_playing ? Icons.pause : Icons.play_arrow),
),
);
}
}
КромеRotationTransition
Кроме того, есть другие части анимации отображения, такие как:FadeTransition
, ScaleTransition
, SizeTransition
, SlideTransition
Ждать.
Анимация героя
Анимация героя относится к анимации элемента, перемещающегося со старой страницы на новую страницу при переключении страницы. Анимация героя требует использования двухHero
Реализация управления: один используется на старой странице, а другой — на новой странице. дваHero
Элементы управления должны использовать те жеtag
свойств и не может сочетаться с другимиtag
повторить.
// 页面 1
import 'package:flutter/material.dart';
import 'hero_animation_page2.dart';
String cake1 = 'assets/images/cake01.jpg';
String cake2 = 'assets/images/cake02.jpg';
class HeroAnimationPage1 extends StatelessWidget {
GestureDetector buildRowItem(context, String image) {
return GestureDetector(
onTap: () {
// 跳转到页面 2
Navigator.of(context).push(
MaterialPageRoute(builder: (ctx) {
return HeroAnimationPage2(image: image);
}),
);
},
child: Container(
width: 100,
height: 100,
child: Hero(
// 设置 Hero 的 tag 属性
tag: image,
child: ClipOval(child: Image.asset(image)),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('页面 1')),
body: Column(
children: <Widget>[
SizedBox(height: 40.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
buildRowItem(context, cake1),
buildRowItem(context, cake2),
],
),
],
),
);
}
}
// 页面 2
import 'package:flutter/material.dart';
class HeroAnimationPage2 extends StatelessWidget {
final String image;
const HeroAnimationPage2({@required this.image});
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
expandedHeight: 400.0,
title: Text('页面 2'),
backgroundColor: Colors.grey[200],
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
background: Hero(
// 使用从页面 1 传入的 tag 值
tag: image,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(image),
fit: BoxFit.cover,
),
),
),
),
),
),
SliverList(
delegate: SliverChildListDelegate(
<Widget>[
Container(height: 600.0, color: Colors.grey[200]),
],
),
),
],
),
);
}
}
Чередующаяся анимация
Чересстрочная анимация — это анимация, состоящая из серии небольших анимаций. Каждая небольшая анимация может быть непрерывной или прерывистой, а также может накладываться друг на друга. Ключевым моментом является использованиеInterval
Виджет устанавливает временной интервал для каждой небольшой анимации и диапазон значений для каждой анимации.Tween
, и, наконец, используйтеAnimationController
Управляет общим состоянием анимации.
Interval
унаследовалCurve
класс, установив свойстваbegin
а такжеend
чтобы определить рабочий диапазон этой маленькой анимации.
class Interval extends Curve {
/// 动画起始点
final double begin;
/// 动画结束点
final double end;
/// 动画缓动曲线
final Curve curve;
/// ...
}
Это чересстрочная анимация, состоящая из 5 небольших анимаций, ширина, высота, цвет, закругленные углы, граница, каждая анимация имеет свой интервал анимации.
import 'package:flutter/material.dart';
class StaggeredAnimationPage extends StatefulWidget {
@override
_StaggeredAnimationPageState createState() => _StaggeredAnimationPageState();
}
class _StaggeredAnimationPageState extends State<StaggeredAnimationPage>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _width;
Animation<double> _height;
Animation<Color> _color;
Animation<double> _border;
Animation<BorderRadius> _borderRadius;
void _play() {
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
}
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
);
_width = Tween<double>(
begin: 100,
end: 300,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(
0.0,
0.2,
curve: Curves.ease,
),
),
);
_height = Tween<double>(
begin: 100,
end: 300,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(
0.2,
0.4,
curve: Curves.ease,
),
),
);
_color = ColorTween(
begin: Colors.blue,
end: Colors.yellow,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(
0.4,
0.6,
curve: Curves.ease,
),
),
);
_borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(0.0),
end: BorderRadius.circular(150.0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(
0.6,
0.8,
curve: Curves.ease,
),
),
);
_border = Tween<double>(
begin: 0,
end: 25,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.8, 1.0),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('交织动画')),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return Container(
width: _width.value,
height: _height.value,
decoration: BoxDecoration(
color: _color.value,
borderRadius: _borderRadius.value,
border: Border.all(
width: _border.value,
color: Colors.orange,
),
),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: _play,
child: Icon(Icons.refresh),
),
);
}
}
Физическая анимация
Анимация — это аналоговая анимация движения объекта физического реального мира. Необходимо установить спортивную модель объекта с учетом местонахождения объекта, например, на это движение влияют факторы высоты падения объекта, ускорение свободного падения, силы реакции земли и т.д.
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class ThrowAnimationPage extends StatefulWidget {
@override
_ThrowAnimationPageState createState() => _ThrowAnimationPageState();
}
class _ThrowAnimationPageState extends State<ThrowAnimationPage> {
// 球心高度
double y = 70.0;
// Y 轴速度
double vy = -10.0;
// 重力
double gravity = 0.1;
// 地面反弹力
double bounce = -0.5;
// 球的半径
double radius = 50.0;
// 地面高度
final double height = 700;
// 下落方法
void _fall(_) {
y += vy;
vy += gravity;
// 如果球体接触到地面,根据地面反弹力改变球体的 Y 轴速度
if (y + radius > height) {
y = height - radius;
vy *= bounce;
} else if (y - radius < 0) {
y = 0 + radius;
vy *= bounce;
}
setState(() {});
}
@override
void initState() {
super.initState();
// 使用一个 Ticker 在每次更新界面时运行球体下落方法
Ticker(_fall)..start();
}
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(title: Text('物理动画')),
body: Column(
children: <Widget>[
Container(
height: height,
child: Stack(
children: <Widget>[
Positioned(
top: y - radius,
left: screenWidth / 2 - radius,
child: Container(
width: radius * 2,
height: radius * 2,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
],
),
),
Expanded(child: Container(color: Colors.blue)),
],
),
);
}
}
Суммировать
В этой статье представлены различные типы анимации во Flutter, а именно
- Неявная анимация
- явная анимация
- Анимация героя
- Чередующаяся анимация
- Анимация на основе физики
Анимация флаттера основана на типизированномAnimation
объект,Widgets
Повторите запуск, прочитав текущее значение объекта анимации и прослушивая изменения состояния.build
Функция, постоянно изменяющая пользовательский интерфейс для формирования эффекта анимации.
Основными элементами анимации являются
-
Animation
объект анимации -
AnimationController
контроллер анимации -
Tween
диапазон значений анимации -
Curve
кривая движения анимации
Ссылаться на
Flutter animation basics with implicit animations
Directional animations with built-in explicit animations
Введение в анимационные эффекты
Реализация анимационных эффектов в приложениях Flutter
В этой статье используетсяmdniceнабор текста