I want to accomplish slide to right transition in my flutter application.
The problem is that route transition kinda creates new instance of page that I want to transit from, and so ListView
scroll resets.
See a video
That's how I create a new route
/// @oldRoute needed cause this route transition utilizes `SlideStackRightRoute`
Route createSettingsRoute(Widget oldRoute) {
return SlideStackRightRoute(exitPage: oldRoute, enterPage: SettingsRoute());
}
And finally slide transition class itself
import 'package:flutter/material.dart';
/// Creates cupertino-like route transition, where new route pushes old from right to left
class SlideStackRightRoute extends PageRouteBuilder {
final Widget enterPage;
final Widget exitPage;
static var exBegin = Offset(0.0, 0.0);
static var exEnd = Offset(-0.5, 0.0);
static var entBegin = Offset(1.0, 0.0);
static var entEnd = Offset.zero;
static var curveIn = Curves.easeOutSine;
static var curveOut = Curves.easeInSine;
SlideStackRightRoute({@required this.exitPage, @required this.enterPage})
: super(
transitionDuration: Duration(milliseconds: 400),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
enterPage,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
Stack(
children: <Widget>[
SlideTransition(
position: Tween(begin: exBegin, end: exEnd)
.chain(CurveTween(curve: curveIn))
.chain(CurveTween(curve: curveOut))
.animate(animation),
child: Container(
foregroundDecoration: BoxDecoration(
color: Colors.black.withOpacity(animation.value / 2),
),
child: exitPage),
),
SlideTransition(
position: Tween(begin: entBegin, end: entEnd)
.chain(CurveTween(curve: curveIn))
.chain(CurveTween(curve: curveOut))
.animate(animation),
child: enterPage,
)
],
),
);
}
the way i created a "slide-out" animation in the question wasn't correct. in terms of the framework it's called a secondaryAnimation
to create your own secondary animation, you need to use a PageRouteBuilder
transitionBuilder property
example can the code below, which produces such animation, and there's no problem with a ListView
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primaryColor: Colors.white),
initialRoute: '/',
onGenerateInitialRoutes: (initialRoute) => [createCustomTransition(HomeScreen())],
onGenerateRoute: (settings) {
if (settings.name == '1') {
return createCustomTransition(SomeScreen());
}
return createCustomTransition(OtherScreen());
},
debugShowCheckedModeBanner: false,
);
}
}
/// Will create a custom route transition for you.
PageRouteBuilder createCustomTransition(Widget screen) {
return PageRouteBuilder(
transitionDuration: const Duration(milliseconds: 700),
reverseTransitionDuration: const Duration(milliseconds: 700),
pageBuilder: (context, animation, secondaryAnimation) => screen,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final slideAnimation = Tween(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(CurvedAnimation(
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
parent: animation,
));
final slideOutAnimation = Tween(
begin: Offset.zero,
end: const Offset(-0.3, 0.0),
).animate(CurvedAnimation(
curve: Curves.easeOutCubic,
reverseCurve: Curves.easeInCubic,
parent: secondaryAnimation,
));
return SlideTransition(
position: slideAnimation,
child: SlideTransition(
position: slideOutAnimation,
child: child,
),
);
},
);
}
class HomeScreen extends StatelessWidget {
HomeScreen({Key key}) : super(key: key);
final List<int> list = List.generate(1000, (index) => index);
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) => ListTile(
title: Center(
child: Text(list[index].toString()),
)
),
)
),
ElevatedButton(
child: const Text('go to some screen'),
onPressed: () {
Navigator.of(context).pushNamed('1');
},
),
],
),
),
);
}
}
class SomeScreen extends StatelessWidget {
const SomeScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(),
body: Center(
child: ElevatedButton(
child: const Text('go to other screen'),
onPressed: () {
Navigator.of(context).pushNamed('');
},
),
),
);
}
}
class OtherScreen extends StatelessWidget {
const OtherScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue,
appBar: AppBar(),
);
}
}
according to docs PageRouteBuilder
is
A utility class for defining one-off page routes in terms of callbacks.
it's perfrect for general use, but if you are building something more complex, i suggest taking a look at some framework page route animation impementations and different class relationships they have
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With