Я полностью застрял с этим. Я хочу создать собственный маршрут страницы, который будет анимировать как 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 перед нажатием маршрут как этот:
_animationController.forward();
Navigator.of(context).push(
FromMenuRoute(prevPage: widget, nextPage: nextPageWidget)
);
И это сработало. Анимация страницы запускалась вместе с переходом страницы. Но мне не удалось развернуть контроллер, когда мне нужно было проложить маршрут. Я имею в виду, конечно, я мог бы, например, в методе didWidgetUpdate, но это не имело никакого эффекта, потому что виджет (который в этом примере называется nextPage) потерял свой контекст, а контроллер анимации анимировал еще одну копию виджета, которая не отображалась до переход поп закончился. Во время выполнения поп-перехода он отображал старую копию «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