#flutter #dart #flutter-web #flutter-animation
#flutter #dart #flutter-web #flutter-анимация
Вопрос:
У меня есть 2 страницы ( Page1
и Page2
) Для навигации между ними у меня есть пользовательский PrimaryMenu
виджет, который одинаков для обеих страниц. Содержится PrimaryMenu
в BodyPage1
и BodyPage2
соответственно. У меня также есть пользовательский Header
виджет. Обе страницы имеют анимацию, как и заголовок.
Что я собираюсь сделать, это нажать на один из InkWell
виджетов, затем анимация меняется на текущую страницу, затем вызывается новая страница. Я знаю, как вызвать новую страницу, у меня есть приблизительное представление о том, как ее использовать GlobalKey
, но я начинаю думать, что с этим ничего нельзя сделать GlobalKey
. Ниже я покажу отдельные виджеты, которые у меня есть: ссылка на dartpad на всякий случай — https://dartpad.dev/88b8536ea7888b5621d7d80acdcd2887
class Header extends StatefulWidget {
@override
_HeaderState createState() => _HeaderState();
}
class _HeaderState extends State<Header> with SingleTickerProviderStateMixin {
AnimationController transitionAnimation;
@override
void initState() {
super.initState();
transitionAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
transitionAnimation.forward();
}
@override
Widget build(BuildContext context) {
return Container(
color: Color(0x88dddddd),
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 8,
),
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve: const Interval(0, 0.3,
curve: Curves.easeInOutBack),
parent: transitionAnimation)),
child: child,
);
},
child: Container(
height: 100,
width: MediaQuery.of(context).size.width * 0.135,
color: Colors.pink,
),
),
Expanded(
child: Container(),
),
Container(
width: 100,
height: 50,
color: Colors.purple,
),
SizedBox(
width: 8,
),
Container(
height: 50,
width: 50,
color: Colors.amber,
),
SizedBox(
width: 8,
)
],
));
}
}
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 120),
child: Header(),
),
body: BodyPage1(),
);
}
}
class PrimaryMenu extends StatefulWidget {
@override
_PrimaryMenuState createState() => _PrimaryMenuState();
}
class _PrimaryMenuState extends State<PrimaryMenu> {
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width * 0.15,
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 40,
width: MediaQuery.of(context).size.width * 0.135,
color: Colors.grey,
child: InkWell(
onTap: () {
print('1');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page1(),
));
},
)),
SizedBox(height: 16),
Container(
height: 40,
width: MediaQuery.of(context).size.width * 0.135,
color: Colors.black,
child: InkWell(
onTap: () {
print('2');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page2(),
));
},
)),
],
));
}
}
class BodyPage1 extends StatefulWidget {
@override
_BodyPage1State createState() => _BodyPage1State();
}
class _BodyPage1State extends State<BodyPage1>
with SingleTickerProviderStateMixin {
AnimationController transitionAnimation;
@override
void initState() {
super.initState();
transitionAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
transitionAnimation.forward();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve:
const Interval(0, 0.3, curve: Curves.easeInOutBack),
parent: transitionAnimation)),
child: child,
);
},
child: PrimaryMenu()),
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve: const Interval(0.3, 1, curve: Curves.easeIn),
parent: transitionAnimation)),
child: child);
},
child: Padding(
padding: EdgeInsets.only(top: 140, left: 20, right: 20, bottom: 20),
child: Container(
height: MediaQuery.of(context).size.height - 140,
width: (MediaQuery.of(context).size.width * .85) - 40,
color: Colors.grey,
),
),
)
],
);
}
}
class Page2 extends StatefulWidget {
@override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> {
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 120),
child: Header(),
),
body: BodyPage2(),
);
}
}
class BodyPage2 extends StatefulWidget {
@override
_BodyPage2State createState() => _BodyPage2State();
}
class _BodyPage2State extends State<BodyPage2>
with SingleTickerProviderStateMixin {
AnimationController transitionAnimation;
@override
void initState() {
super.initState();
transitionAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
transitionAnimation.forward();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve:
const Interval(0, 0.3, curve: Curves.easeInOutBack),
parent: transitionAnimation)),
child: child,
);
},
child: PrimaryMenu()),
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve: const Interval(0.3, 1, curve: Curves.easeIn),
parent: transitionAnimation)),
child: child);
},
child: Padding(
padding: EdgeInsets.only(top: 140, left: 20, right: 20, bottom: 20),
child: Container(
height: MediaQuery.of(context).size.height - 140,
width: (MediaQuery.of(context).size.width * .85) - 40,
color: Colors.black,
),
),
)
],
);
}
}
Также я настроил панель управления, показывающую, что мне удалось сделать с помощью GlobalKey, я могу заставить ее работать, только если я использую FloatingActionButton
на Scaffold
— https://dartpad.dev/5979f44ecaa9cf2e22b4ce0cc9c23aa8
Извините, что кода много, я постарался максимально сжать его
Ответ №1:
Все, что вам нужно сделать, это передать AnimationController из соответствующего BodyPage в ваш PrimaryMenu, который отвечает за вызов Page1 и Page2. Как только AnimationController станет доступен для PrimaryMenu, он сначала отменит анимацию и .затем вызовите соответствующую страницу. Пожалуйста, посмотрите рабочий код ниже :
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(visualDensity: VisualDensity.adaptivePlatformDensity),
debugShowCheckedModeBanner: false,
home: Page1(),
);
}
}
class Header extends StatefulWidget {
@override
_HeaderState createState() => _HeaderState();
}
class _HeaderState extends State<Header> with SingleTickerProviderStateMixin {
AnimationController transitionAnimation;
@override
void initState() {
super.initState();
transitionAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
transitionAnimation.forward();
}
@override
Widget build(BuildContext context) {
return Container(
color: const Color(0x88dddddd),
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(
width: 8,
),
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve: const Interval(0, 0.3,
curve: Curves.easeInOutBack),
parent: transitionAnimation)),
child: child,
);
},
child: Container(
height: 100,
width: MediaQuery.of(context).size.width * 0.135,
color: Colors.pink,
),
),
Expanded(
child: Container(),
),
Container(
width: 100,
height: 50,
color: Colors.purple,
),
const SizedBox(
width: 8,
),
Container(
height: 50,
width: 50,
color: Colors.amber,
),
const SizedBox(
width: 8,
)
],
));
}
}
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 120),
child: Header(),
),
body: BodyPage1(),
);
}
}
class PrimaryMenu extends StatefulWidget {
final AnimationController controller;
const PrimaryMenu({Key key, this.controller}) : super(key: key);
@override
_PrimaryMenuState createState() => _PrimaryMenuState();
}
class _PrimaryMenuState extends State<PrimaryMenu> {
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width * 0.15,
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 40,
width: MediaQuery.of(context).size.width * 0.135,
color: Colors.grey,
child: InkWell(
onTap: () async {
print('1');
await widget.controller
.reverse()
.then((value) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page1(),
)));
},
)),
const SizedBox(height: 16),
Container(
height: 40,
width: MediaQuery.of(context).size.width * 0.135,
color: Colors.black,
child: InkWell(
onTap: () async {
print('2');
await widget.controller
.reverse()
.then((value) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page2(),
)));
},
)),
],
));
}
}
class BodyPage1 extends StatefulWidget {
@override
_BodyPage1State createState() => _BodyPage1State();
}
class _BodyPage1State extends State<BodyPage1>
with SingleTickerProviderStateMixin {
AnimationController transitionAnimation;
@override
void initState() {
super.initState();
transitionAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
transitionAnimation.forward();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve:
const Interval(0, 0.3, curve: Curves.easeInOutBack),
parent: transitionAnimation)),
child: child,
);
},
child: PrimaryMenu(
controller: transitionAnimation,
)),
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve: const Interval(0.3, 1, curve: Curves.easeIn),
parent: transitionAnimation)),
child: child);
},
child: Padding(
padding: const EdgeInsets.only(
top: 140, left: 20, right: 20, bottom: 20),
child: Container(
height: MediaQuery.of(context).size.height - 140,
width: (MediaQuery.of(context).size.width * .85) - 40,
color: Colors.grey,
),
),
)
],
);
}
}
class Page2 extends StatefulWidget {
@override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> {
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 120),
child: Header(),
),
body: BodyPage2(),
);
}
}
class BodyPage2 extends StatefulWidget {
@override
_BodyPage2State createState() => _BodyPage2State();
}
class _BodyPage2State extends State<BodyPage2>
with SingleTickerProviderStateMixin {
AnimationController transitionAnimation;
@override
void initState() {
super.initState();
transitionAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
transitionAnimation.forward();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve:
const Interval(0, 0.3, curve: Curves.easeInOutBack),
parent: transitionAnimation)),
child: child,
);
},
child: PrimaryMenu(
controller: transitionAnimation,
)),
AnimatedBuilder(
animation: transitionAnimation,
builder: (context, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-2, 0), end: const Offset(0, 0))
.animate(CurvedAnimation(
curve: const Interval(0.3, 1, curve: Curves.easeIn),
parent: transitionAnimation)),
child: child);
},
child: Padding(
padding: const EdgeInsets.only(
top: 140, left: 20, right: 20, bottom: 20),
child: Container(
height: MediaQuery.of(context).size.height - 140,
width: (MediaQuery.of(context).size.width * .85) - 40,
color: Colors.black,
),
),
)
],
);
}
}