我已经做过类似的事情,但不幸的是我的代码还包含了许多其他内容,而且这样做相对复杂,因此我必须分离出一些东西来使示例更具代表性,但我现在无法做到。 我将解释我所做的事情的一般概念,虽然可能有更好的方法。
您想编写一个带有State的StatefulWidget,该State还扩展了NavigatorObserver(您可能可以使用无状态小部件,但我认为不行)。 我个人将其置于树中导航器之上(即在其构建函数中构建导航器),但您很可能也可以将其“放在”导航器旁边。
覆盖NavigatorObserver的didPush,didRemove,didPop等方法。 在每个方法内,调用setState并保存动画和其他参数,例如:
class NavigationFaderState extends State<NavigationFader> with NavigatorObserver {
Animation _animation;
@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并根据其是否存在以及您可能想设置的任何其他参数进行动画处理(例如,一个标志用于动画处理,以及向前或向后是否有利 - 我认为'pop'动画可能从0开始,并像推送动画一样到1,但我可能错了)。
然后,您可以将此动画连接到您想要动画处理导航栏的方式,可能使用AnimatedBuilder或直接连接动画,或者其他方式。如果有关于所有这些工作原理的任何具体问题,请发表评论,我将添加一些注释等。
希望能有所帮助=)
编辑:附带完整代码示例。对于记录,我不提议这段代码非常好,或者这是您应该做的事情。但这是解决问题的一种方法。在真正的应用程序中使用它之前,值得测试它并可能添加一些断言以检查状态等。
import '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) {
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) {
}
@override
void didStartUserGesture() {
}
@override
void didStopUserGesture() {
}
}
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();
}
}