我做过类似的事情,但是不幸的是我的代码还包含很多其他内容,而且要做起来相对繁琐,所以我不得不将它们分解成一个例子,这比我现在能做的要多。我将解释我所做的一般概念。也许还有更好的方法可以做到这一点。
您想编写一个StatefulWidget,其State也扩展了NavigatorObserver(您可以使用无状态的widget,但我认为不是)。我个人将其放置在树中导航器的上方(即,它在其“
build”功能中构建了导航器),但是您很可能也将其置于“导航器”的旁边。
覆盖NavigatorObserver中的didPush,didRemove,didPop等方法。在其中的每一个中,调用setState并保存动画和其他参数,如下所示:
class NavigationFaderState extends State<NavigationFader> with NavigatorObserver { Animation _animation; // whatever else you need, maybe starting/finishing opacity or position etc. @override void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { setState(() { _animation = route.animation; } route.animation.addStatusListener((status) { if (status = AnimationStatus.completed) { setState(() { _animation = null; }); } }); } ....}在您的构建函数中,您需要根据_animation和animate以及是否可能要设置的其他参数(例如,是否要进行动画处理的标志以及前进或后退的标志)进行检查-
我相信“
pop”动画已从0开始并与推入动画一样升至1,但我可能错了)。然后,您可以将该动画连接到想要设置导航栏动画的位置,可以使用AnimatedBuilder或直接将动画连接起来,等等。如果有关于这一切工作方式的任何特定问题,请发表评论,我将添加一些评论,等等。
希望有帮助=)
编辑:完整的代码示例。作为记录,我不建议这段代码那么好,或者您应该这样做。但这是解决问题的一种方法。在实际应用中使用它之前,值得对其进行测试,并可能添加一些断言以检查状态等。
导入’package:flutter / material.dart’;
void main() => runApp(new MyApp());class MyApp extends StatelessWidget { PushListener listener = new PushListener(); @override Widget build(BuildContext context) { return new WidgetsApp( locale: new Locale("en"), navigatorObservers: [listener], builder: (context, child) { // this is here rather than outside the WidgetsApp so that it // gets access to directionality, text styles, etc return new Scaffold( body: child, bottomNavigationBar: new ColorChangingNavigationBar(key: listener.navBarKey), ); }, onGenerateRoute: (settings) { switch (settings.name) { case '/': return new MaterialPageRoute( settings: settings, builder: (context) => Column( children: <Widget>[new Text( "I have a green nav bar when you open me and blue when you come back"),new RaisedButton( onPressed: () { Navigator.pushNamed(context, "/red"); }, child: new Text("Next"),), ], ), ); case '/red': return new MaterialPageRoute( settings: settings, builder: (context) => Column( children: <Widget>[new Text("I have a red nav bar"),new RaisedButton( onPressed: () { Navigator.pop(context); },) ], ), ); } }, color: Colors.blue, ); }}class PushListener extends NavigatorObserver { GlobalKey<ColorChangingNavigationBarState> navBarKey = new GlobalKey(); @override void didPop(Route route, Route previousRoute) { if (route is ModalRoute && navBarKey.currentState != null) { var name = route.settings.name; var color = name == "/" ? Colors.red.shade500 : Colors.blue.shade500; var animation = new ReverseAnimation(route.animation); print("Popping & changing color to: ${name == "/" ? "red" : "blue"}"); navBarKey.currentState.setAnimating(animation, color); } } @override void didPush(Route route, Route previousRoute) { if (route is ModalRoute && navBarKey.currentState != null) { var name = route.settings.name; var color = name == "/" ? Colors.blue.shade500 : Colors.red.shade500; print("Pushing & changing color to: ${name == "/" ? "red" : "blue"}"); var animation = route.animation; navBarKey.currentState.setAnimating(animation, color); } } @override void didRemove(Route route, Route previousRoute) { // probably don't need } @override void didStartUserGesture() { // might want to do if gestures are supported with whichever type of // route you're using. } @override void didStopUserGesture() { // if you implement didStartUserGesture }}class ColorChangingNavigationBar extends StatefulWidget { final Color startColor; ColorChangingNavigationBar( {Key key, this.startColor = const Color.fromRGBO(0, 255, 0, 1.0)}) : super(key: key); @override State<StatefulWidget> createState() => new ColorChangingNavigationBarState();}class _ColorAnimationInfo { final Animation animation; final Tween<Color> colorTween; final AnimationStatusListener statusListener; _ColorAnimationInfo(this.animation, this.colorTween, this.statusListener);}class ColorChangingNavigationBarState extends State<ColorChangingNavigationBar> { @override void initState() { _toColor = widget.startColor; super.initState(); } Color _toColor; _ColorAnimationInfo _colorAnimationInfo; void setAnimating(Animation animation, Color to) { var fromColor; if (_colorAnimationInfo != null) { fromColor = _colorAnimationInfo.colorTween .lerp(_colorAnimationInfo.animation.value); _colorAnimationInfo.animation .removeStatusListener(_colorAnimationInfo.statusListener); } else { fromColor = _toColor; } var statusListener = (state) { if (state == AnimationStatus.completed || state == AnimationStatus.dismissed) { setState(() { _colorAnimationInfo = null; }); } }; animation.addStatusListener(statusListener); setState(() { _toColor = to; Tween<Color> colorTween = new ColorTween(begin: fromColor, end: to); _colorAnimationInfo = new _ColorAnimationInfo(animation, colorTween, statusListener); }); } @override Widget build(BuildContext context) { if (_colorAnimationInfo != null) { return new AnimatedBuilder( animation: _colorAnimationInfo.animation, builder: (context, child) { return new Container( color: _colorAnimationInfo.colorTween .lerp(_colorAnimationInfo.animation.value), height: 30.0, ); }); } else { return new Container( color: _toColor, height: 30.0, ); } } @override void dispose() { if (_colorAnimationInfo != null) { _colorAnimationInfo.animation.removeStatusListener(_colorAnimationInfo.statusListener); } _colorAnimationInfo = null; super.dispose(); }}


