[英]Flutter. How to make AnimationBuilder listen to Multiple Animations?
class _SomeWidgetWithAnimationsState extends State<SomeWidgetWithAnimations> with TickerProviderStateMixin {
AnimationController firstController;
AnimationController secondController;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
aniamtion: /* Here I want to pass the two animation controllers above */,
builder: (context, child) => /* Something that uses two animations to animate */,
);
}
}
我希望能够监听来自多个Listenable
的事件,其中只需要一个Listenable
。 有没有办法将通知从两个Listenable
路由到一个? 我考虑创建我自己的Listenable
实现,该实现将具有一些方法,例如addSourceListenable(Listenable source)
将订阅Listenable
源,并通过回调通知其自己的订阅者。 但我认为有一种更优雅的方法可以解决这个问题。 也许 RxDart 可以提供一些东西。
对于这个具有多个动画的用例,flutter 有一个自己的概念,称为Staggered Animations
。 你可以在这里读更多关于它的内容:
这是文章提供的完整工作示例:
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
class StaggerAnimation extends StatelessWidget {
StaggerAnimation({ Key key, this.controller }) :
// Each animation defined here transforms its value during the subset
// of the controller's duration defined by the animation's interval.
// For example the opacity animation transforms its value during
// the first 10% of the controller's duration.
opacity = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0, 0.100,
curve: Curves.ease,
),
),
),
width = Tween<double>(
begin: 50.0,
end: 150.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.125, 0.250,
curve: Curves.ease,
),
),
),
height = Tween<double>(
begin: 50.0,
end: 150.0
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.250, 0.375,
curve: Curves.ease,
),
),
),
padding = EdgeInsetsTween(
begin: const EdgeInsets.only(bottom: 16.0),
end: const EdgeInsets.only(bottom: 75.0),
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.250, 0.375,
curve: Curves.ease,
),
),
),
borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(4.0),
end: BorderRadius.circular(75.0),
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.375, 0.500,
curve: Curves.ease,
),
),
),
color = ColorTween(
begin: Colors.indigo[100],
end: Colors.orange[400],
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.500, 0.750,
curve: Curves.ease,
),
),
),
super(key: key);
final Animation<double> controller;
final Animation<double> opacity;
final Animation<double> width;
final Animation<double> height;
final Animation<EdgeInsets> padding;
final Animation<BorderRadius> borderRadius;
final Animation<Color> color;
// This function is called each time the controller "ticks" a new frame.
// When it runs, all of the animation's values will have been
// updated to reflect the controller's current value.
Widget _buildAnimation(BuildContext context, Widget child) {
return Container(
padding: padding.value,
alignment: Alignment.bottomCenter,
child: Opacity(
opacity: opacity.value,
child: Container(
width: width.value,
height: height.value,
decoration: BoxDecoration(
color: color.value,
border: Border.all(
color: Colors.indigo[300],
width: 3.0,
),
borderRadius: borderRadius.value,
),
),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
builder: _buildAnimation,
animation: controller,
);
}
}
class StaggerDemo extends StatefulWidget {
@override
_StaggerDemoState createState() => _StaggerDemoState();
}
class _StaggerDemoState extends State<StaggerDemo> with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 2000),
vsync: this
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Future<void> _playAnimation() async {
try {
await _controller.forward().orCancel;
await _controller.reverse().orCancel;
} on TickerCanceled {
// the animation got canceled, probably because we were disposed
}
}
@override
Widget build(BuildContext context) {
timeDilation = 10.0; // 1.0 is normal animation speed.
return Scaffold(
appBar: AppBar(
title: const Text('Staggered Animation'),
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
_playAnimation();
},
child: Center(
child: Container(
width: 300.0,
height: 300.0,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.1),
border: Border.all(
color: Colors.black.withOpacity(0.5),
),
),
child: StaggerAnimation(
controller: _controller.view
),
),
),
),
);
}
}
void main() {
runApp(MaterialApp(home: StaggerDemo()));
}
您几乎可以做所有事情,并将其链接在逻辑中。 我建议您只是指导将文档扔在那里,它得到了很好的解释。
看看Listenable.merge(List<Listenable?> listenables)
,它返回一个 Listenable,当任何给定的 Listenables 本身触发时触发。 希望我对你有所帮助:)
https://api.flutter.dev/flutter/foundation/Listenable/Listenable.merge.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.