你们中的大多数人已经知道,Flutter提供了库比蒂诺导航过渡,该过渡代表当然通向以前的路线时本地iOS行为。您可以从设备的左边缘开始滑动,并启动导航动画。除非用户结束触摸屏幕,否则用户控制当前(上)和上一个(下)路由的位置。 根据发布位置和速度,无论是否弹出屏幕,动画控制器都会占据工作的其余部分。 我想实现与此相反的相反。当用户开始从屏幕的右边缘向左滑动时,将检测到手势。新路线将被创建并放在右边。用户可以将新路线拖到左侧(进入场景)。触摸发布后,将决定将新路线(完成)中心或放开(取消)。 例如,可以在Safari浏览器中观察到这种行为。您可以通过从左边缘开始滑动来向后导航。此外,您可以通过从屏幕的右端开始滑动来向前导航。
此外,也可以在Tiktok应用中体验类似的UI/UX行为。在“ For You”屏幕上观看视频(这是Tiktok的默认主页)时,用户可以开始将屏幕从右到左开始拖动屏幕,当检测到手势时,将显示当前内容所有者的配置文件屏幕。如上所述,用户将通过拖动来控制位置。当用户结束时,它将根据情况完成或取消导航。 问题是:自从beta早期以来,我就成为了扑朔迷离的力量使用者。直到今天,我进行了非常复杂的UX实现。但是,这种类型的导航并不需要问题,也没有想到。
我对颤音源代码,互联网,扑朔迷离,pub.dev等进行了深入的研究。但是,我找不到逻辑上的简单解决方案。有人知道该怎么做吗?的确,我们可以使用Cupertinopageroute并延伸到它上,但我目前只是停止了。
方面注意:最终结果可能就像视差效果或pageview。我面临同样的问题,但是没有人会有这个好的Quetion。
无论我要求chatgpt实现这种效果,这与您的欲望行为确实相似。我希望这可以帮助他人推荐它。 这是
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,
),
),
);
}
}