gpt4 book ai didi

Flutter 使用内部动画为两条路线设置动画

转载 作者:行者123 更新时间:2023-12-04 12:24:32 26 4
gpt4 key购买 nike

我完全被它困住了。我想创建一个自定义页面路由,它将同时为 IN 和 OUT 页​​面设置动画。路线本身的动画是一项简单的任务,我是这样做的:

    import 'package:flutter/material.dart';

class FromMenuRoute extends PageRouteBuilder {

final Widget nextPage;
final Widget prevPage;

FromMenuRoute({this.prevPage, this.nextPage}) : super(
transitionDuration: Duration(milliseconds: 500),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return nextPage;
},
maintainState: false,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
var colorTheme = CustomThemeData.of(context).colorTheme;
return Material(
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-0.3, 0.0),
).animate(animation),
child: prevPage,
),
SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: AnimatedBuilder(
animation: animation,
builder: (c, w) {
return Material(
shadowColor: colorTheme.textColor,
elevation: 30.0 * animation.value,
child: nextPage
);
},
),
)
],
),
);
}
);
}

但问题是我还想在这些页面中运行一些动画,而不仅仅是为页面小部件本身设置动画。我不知道我该怎么做。

我正在使用这样的路线

Navigator.of(context).push(
FromMenuRoute(prevPage: widget, nextPage: nextPageWidget)
);

我的第一个想法是在像这样推送路由之前在 OUT 页​​面中启动一个动画 Controller :

_animationController.forward();
Navigator.of(context).push(
FromMenuRoute(prevPage: widget, nextPage: nextPageWidget)
);

它奏效了。页面动画与页面过渡一起运行。但是当我需要弹出路由时,我无法反转 Controller 。
我的意思是,我当然可以,例如在 didWidgetUpdate 方法中,但它没有效果,因为小部件(在本例中称为 nextPage)丢失了它的上下文,并且动画 Controller 动画了小部件的另一个副本,直到弹出过渡结束才显示。
当流行过渡运行时,它显示了“nextPage”的旧副本

第二个想法是使用 GlobalKey 来保持小部件的状态,该小部件也因错误而失败
使用 2 个重复的全局键。

在我的 FromMenuRoute 中,理想的选择是这样的

SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-0.3, 0.0),
).animate(animation),
child: prevPage.copyWith(animation: animation), // but I understand this can't be done
),

所以我已经没有好主意了。我不想以某种非常棘手的方式制作它。也许有一些我不知道的更好的解决方案。请分享它,如果你知道如何解决这个问题

这是我想要实现的详细示例

import 'package:flutter/material.dart';

class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}

class _Page1State extends State<Page1> with SingleTickerProviderStateMixin {


AnimationController _animationController;

@override
void initState() {
_animationController = AnimationController(
vsync: this,
lowerBound: 0.0,
upperBound: 1.0,
duration: Duration(milliseconds: 3000)
);
super.initState();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}


@override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: double.infinity,
height: 60.0,
color: Colors.amber,
child: Stack(
children: <Widget>[
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: Offset(3.0, 0.0),
).animate(_animationController),
child: Container(
height: 60.0,
width: 60.0,
color: Colors.blue,
),
),
],
),
),
SizedBox(height: 100.0,),
RaisedButton(
child: Text('Add new route'),
onPressed: () {
/// calling here doe not affect animation because
/// a new widget is created on top of this
/// but is I call it from initState() I won't have access to the
/// controller later, when I need to revert the animation
_animationController.forward();
Navigator.of(context).push(
FromMenuRoute(prevPage: widget, nextPage: Page2())
);
},
),
],
),
);
}
}


class Page2 extends StatefulWidget {
@override
_Page2State createState() => _Page2State();
}

class _Page2State extends State<Page2> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
width: double.infinity,
height: double.infinity,
);
}
}


class FromMenuRoute extends PageRouteBuilder {

final Widget nextPage;
final Widget prevPage;

FromMenuRoute({this.prevPage, this.nextPage}) : super(
transitionDuration: Duration(milliseconds: 3000),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return nextPage;
},
maintainState: true,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return Material(
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-0.3, 0.0),
).animate(animation),
child: prevPage,
),

SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: AnimatedBuilder(
animation: animation,
builder: (c, w) {
return Opacity(
opacity: .8,
child: Material(
shadowColor: Colors.black,
elevation: 30.0 * animation.value,
child: nextPage
),
);
},
),
)
],
),
);
}
);
}

我需要在页面转换开始时开始移动一个蓝色方块,并在路线 pop 上恢复该方块的动画

最佳答案

我刚刚想到了一个解决方案。我可以通过访问动画

ModalRoute.of(context).animation;

这是工作示例

import 'package:flutter/material.dart';

class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}

class _Page1State extends State<Page1> with SingleTickerProviderStateMixin {

@override
Widget build(BuildContext context) {
var modalRoute = ModalRoute.of(context);

return Container(
color: Colors.red,
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: double.infinity,
height: 60.0,
color: Colors.amber,
child: Stack(
children: <Widget>[
AnimatedBuilder(
animation: modalRoute.animation,
builder: (c, w) {
var isCompleted = modalRoute.animation.status == AnimationStatus.completed;
var posX = 150.0 * modalRoute.animation.value;
if (isCompleted) {
posX = 0;
}
return Transform(
transform: Matrix4.translationValues(posX, 0, 0),
child: Container(
height: 60.0,
width: 60.0,
color: Colors.blue,
),
);
},
),
],
),
),
SizedBox(height: 100.0,),
RaisedButton(
child: Text('Add new route'),
onPressed: () {
Navigator.of(context).push(
FromMenuRoute(prevPage: widget, nextPage: Page2())
);
},
),
],
),
);
}
}


class Page2 extends StatefulWidget {
@override
_Page2State createState() => _Page2State();
}

class _Page2State extends State<Page2> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
width: double.infinity,
height: double.infinity,
);
}
}


class FromMenuRoute extends PageRouteBuilder {

final Widget nextPage;
final Widget prevPage;

FromMenuRoute({this.prevPage, this.nextPage}) : super(
transitionDuration: Duration(milliseconds: 3000),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return nextPage;
},
maintainState: true,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return Material(
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-0.3, 0.0),
).animate(animation),
child: prevPage,
),

SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: AnimatedBuilder(
animation: animation,
builder: (c, w) {
return Material(
shadowColor: Colors.black,
elevation: 30.0 * animation.value,
child: nextPage
);
},
),
)
],
),
);
}
);
}

关于Flutter 使用内部动画为两条路线设置动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61046775/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com