I am faceing the same question, but there is nobody anwser this good quetion.
However I asked chatGPT to achieve this effect which is really similar to your desire behavior. I hope this can help for others to refer it. Here is code:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: GestureControlledPage(),
);
}
}
class GestureControlledPage extends StatefulWidget {
const GestureControlledPage({super.key});
@override
_GestureControlledPageState createState() => _GestureControlledPageState();
}
class _GestureControlledPageState extends State<GestureControlledPage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
}
void _handleDragUpdate(DragUpdateDetails details) {
// Update the controller's value based on the drag position
double delta = details.primaryDelta! / MediaQuery.of(context).size.width;
_controller.value -= delta;
}
void _handleDragEnd(DragEndDetails details) {
if (_controller.value > 0.5) {
// Complete the transition
Navigator.of(context).push(_createRoute()).then((_) {
_controller.animateBack(.0);
});
} else {
// Revert the transition
_controller.reverse();
}
}
Route _createRoute() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => const NewPage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween =
Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
final offsetAnimation = !animation.isForwardOrCompleted
? animation.drive(tween)
: (_controller..forward()).drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onHorizontalDragUpdate: _handleDragUpdate,
onHorizontalDragEnd: _handleDragEnd,
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Stack(
children: [
// Current page
Transform.translate(
offset: Offset(
-_controller.value * MediaQuery.of(context).size.width,
0),
child: Container(
color: Colors.blue,
child: const Center(
child: Text(
'Swipe to the left to push a new page',
style: TextStyle(color: Colors.white, fontSize: 24),
textAlign: TextAlign.center,
),
),
),
),
// Next page (slides in)
Transform.translate(
offset: Offset(
(1 - _controller.value) *
MediaQuery.of(context).size.width,
0),
child: const NewPage(),
),
],
);
},
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
class NewPage extends StatelessWidget {
const NewPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('New Page'),
),
backgroundColor: Colors.green,
body: const Center(
child: Text(
'This is the new page!',
style: TextStyle(color: Colors.white, fontSize: 24),
textAlign: TextAlign.center,
),
),
);
}
}