问题描述
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,curve: Interval(
0.125,0.250,height = Tween<double>(
begin: 50.0,end: 150.0
).animate(
CurvedAnimation(
parent: controller,curve: Interval(
0.250,0.375,padding = EdgeInsetsTween(
begin: const EdgeInsets.only(bottom: 16.0),end: const EdgeInsets.only(bottom: 75.0),borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(4.0),end: BorderRadius.circular(75.0),curve: Interval(
0.375,0.500,color = ColorTween(
begin: Colors.indigo[100],end: Colors.orange[400],curve: Interval(
0.500,0.750,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 本身触发时触发的 Listenable。
希望我对你有帮助:)
https://api.flutter.dev/flutter/foundation/Listenable/Listenable.merge.html