在Android API上,我们可以使用
overridePendingTransition(int enterAnim, int exitAnim)
定义进入和退出转换。
如何在Flutter中做到这一点?
我已经实现了这段代码
class SlideLeftRoute extends PageRouteBuilder {
final Widget enterWidget;
SlideLeftRoute({this.enterWidget})
: super(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return enterWidget;
},
transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child
);
},
);
}
,但它仅定义输入转换。如何定义退出转场?
更新
想象一下,我执行时有两个屏幕(Screen1和Screen2)
Navigator.push(
context, SlideLeftRoute(enterWidget: Screen2()));
我想将动画应用于Screen1和Screen2而不是不仅应用于Screen2
答案 0 :(得分:3)
好问题,PageRouteBuilder
默认使用AnimationController
来处理动画过渡,因此,当您关闭视图时,它只是从animationController调用“ reverse”方法,您将看到相同的结果您正在使用的动画,但相反。
如果您要在关闭视图时更改动画,可以检查当前动画的状态并与AnimationStatus.reverse
进行比较
这是带有Fade
动画的代码,当它反向显示时。
class SlideLeftRoute extends PageRouteBuilder {
final Widget enterWidget;
SlideLeftRoute({this.enterWidget})
: super(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return enterWidget;
},
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
if (animation.status == AnimationStatus.reverse) {
//do your dismiss animation here
return FadeTransition(
opacity: animation,
child: child,
);
} else {
return SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child);
}
},
);
}
WORKAROUND
class SlideLeftRoute extends PageRouteBuilder {
final Widget enterWidget;
final Widget oldWidget;
SlideLeftRoute({this.enterWidget, this.oldWidget})
: super(
transitionDuration: Duration(milliseconds: 600),
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return enterWidget;
},
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return Stack(
children: <Widget>[
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-1.0, 0.0),
).animate(animation),
child: oldWidget),
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: enterWidget)
],
);
});
}
用法:
Navigator.of(context)
.push(SlideLeftRoute(enterWidget: Page2(), oldWidget: this));
答案 1 :(得分:3)
实现此目的的正确方法是使用PageRouteBuilder对象的transitionBuilder中提供的secondaryAnimation参数。
在这里,您可以在flutter sdk的flutter / lib / src / widgets / routes.dart文件中的文档中了解有关secondaryAnimation参数的更多信息:
///
/// When the [Navigator] pushes a route on the top of its stack, the
/// [secondaryAnimation] can be used to define how the route that was on
/// the top of the stack leaves the screen. Similarly when the topmost route
/// is popped, the secondaryAnimation can be used to define how the route
/// below it reappears on the screen. When the Navigator pushes a new route
/// on the top of its stack, the old topmost route's secondaryAnimation
/// runs from 0.0 to 1.0. When the Navigator pops the topmost route, the
/// secondaryAnimation for the route below it runs from 1.0 to 0.0.
///
/// The example below adds a transition that's driven by the
/// [secondaryAnimation]. When this route disappears because a new route has
/// been pushed on top of it, it translates in the opposite direction of
/// the new route. Likewise when the route is exposed because the topmost
/// route has been popped off.
///
/// ```dart
/// transitionsBuilder: (
/// BuildContext context,
/// Animation<double> animation,
/// Animation<double> secondaryAnimation,
/// Widget child,
/// ) {
/// return SlideTransition(
/// position: AlignmentTween(
/// begin: const Offset(0.0, 1.0),
/// end: Offset.zero,
/// ).animate(animation),
/// child: SlideTransition(
/// position: TweenOffset(
/// begin: Offset.zero,
/// end: const Offset(0.0, 1.0),
/// ).animate(secondaryAnimation),
/// child: child,
/// ),
/// );
/// }
/// ```
这是一个使用secondaryAnimation参数的工作示例:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => Page1(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
final Tween<Offset> offsetTween = Tween<Offset>(begin: Offset(0.0, 0.0), end: Offset(-1.0, 0.0));
final Animation<Offset> slideOutLeftAnimation = offsetTween.animate(secondaryAnimation);
return SlideTransition(position: slideOutLeftAnimation, child: child);
},
);
} else {
// handle other routes here
return null;
}
},
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
backgroundColor: Colors.blue,
body: Center(
child: RaisedButton(
onPressed: () => Navigator.push(
context,
PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => Page2(),
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
final Tween<Offset> offsetTween = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0));
final Animation<Offset> slideInFromTheRightAnimation = offsetTween.animate(animation);
return SlideTransition(position: slideInFromTheRightAnimation, child: child);
},
),
),
child: Text("Go to Page 2"),
),
),
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2"), backgroundColor: Colors.green),
backgroundColor: Colors.green,
body: Center(child: RaisedButton(onPressed: () => Navigator.pop(context), child: Text("Back to Page 1"))),
);
}
}
结果:
答案 2 :(得分:2)
我使用了不同的方式,但是diegodeveloper提供了类似的逻辑
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Page1(),
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page 1"),
leading: Icon(Icons.menu),
),
body: Container(
color: Colors.grey,
child: Center(
child: RaisedButton(
onPressed: () => Navigator.push(context, MyCustomPageRoute(previousPage: this, builder: (context) => Page2())),
child: Text("2nd Page"),
),
),
),
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2")),
body: Container(
color: Colors.blueGrey,
child: Center(
child: RaisedButton(
onPressed: () => Navigator.pop(context),
child: Text("Back"),
),
),
),
);
}
}
class MyCustomPageRoute extends MaterialPageRoute {
final Widget previousPage;
MyCustomPageRoute({this.previousPage, WidgetBuilder builder, RouteSettings settings}) : super(builder: builder, settings: settings);
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget currentPage) {
Animation<Offset> _slideAnimationPage1 = Tween<Offset>(begin: Offset(0.0, 0.0), end: Offset(-1.0, 0.0)).animate(animation);
Animation<Offset> _slideAnimationPage2 = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)).animate(animation);
return Stack(
children: <Widget>[
SlideTransition(position: _slideAnimationPage1, child: previousPage),
SlideTransition(position: _slideAnimationPage2, child: currentPage),
],
);
}
}
答案 3 :(得分:0)
还有另一种方法。 initState()
在oldWidget中被调用的问题不再存在。
void main() => runApp(MaterialApp(theme: ThemeData.dark(), home: HomePage()));
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
body: RaisedButton(
child: Text("Next"),
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (c, a1, a2) => Page2(),
transitionsBuilder: (context, anim1, anim2, child) {
return SlideTransition(
position: Tween<Offset>(end: Offset(0, 0), begin: Offset(1, 0)).animate(anim1),
child: Page2(),
);
},
),
);
},
),
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2")),
body: RaisedButton(
child: Text("Back"),
onPressed: () => Navigator.pop(context),
),
);
}
}