Last active
February 27, 2021 16:31
-
-
Save WesselvanDam/df423bb0ad190743bd7ee13820213489 to your computer and use it in GitHub Desktop.
Minimal code example resulting in an error saying multiple widgets used the same GlobalKey.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
// This widget is the root of your application. | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
home: LandingPage(), | |
); | |
} | |
} | |
// Three final GlobalKeys | |
final List<GlobalKey<FormState>> _formKeys = [ | |
GlobalKey<FormState>(), | |
GlobalKey<FormState>(), | |
GlobalKey<FormState>() | |
]; | |
// The page where users can create a new account by filling in email, name, etc. | |
class RegisterPage extends StatelessWidget { | |
RegisterPage({@required this.registerFormKey}); | |
final GlobalKey<FormState> registerFormKey; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.grey, | |
child: Form( | |
key: registerFormKey, // Line presumably throwing the error | |
child: AutofillGroup( | |
child: Column( | |
children: [ | |
Text("Register"), | |
TextFormField(), | |
], | |
), | |
), | |
), | |
); | |
} | |
} | |
// The page where users can login with their email and password | |
class LoginPage extends StatelessWidget { | |
LoginPage({@required this.loginFormKey}); | |
final GlobalKey<FormState> loginFormKey; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.blue, | |
child: Form( | |
key: loginFormKey, // Line presumably throwing the error | |
child: AutofillGroup( | |
child: Column( | |
children: [ | |
Text("Log in"), | |
TextFormField(), | |
], | |
), | |
), | |
), | |
); | |
} | |
} | |
// The page where users can reset their password | |
class ResetPage extends StatelessWidget { | |
ResetPage({@required this.passwordFormKey}); | |
final GlobalKey<FormState> passwordFormKey; | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.orange, | |
child: Form( | |
key: passwordFormKey, // Line presumably throwing the error | |
child: AutofillGroup( | |
child: Column( | |
children: [ | |
Text("Reset password"), | |
TextFormField(), | |
], | |
), | |
), | |
), | |
); | |
} | |
} | |
// The app's landing page, containing an animated IndexedStack that navigates | |
// through all three of the above declared pages. | |
class LandingPage extends StatefulWidget { | |
// The pages are declared as final variables | |
final RegisterPage registerPage = RegisterPage(registerFormKey: _formKeys[0]); | |
final LoginPage loginPage = LoginPage(loginFormKey: _formKeys[1]); | |
final ResetPage resetScreen = ResetPage(passwordFormKey: _formKeys[2]); | |
@override | |
_LandingPageState createState() => _LandingPageState(); | |
} | |
class _LandingPageState extends State<LandingPage> { | |
int view = 1; | |
int previousView = 1; // Used for animation (the error breaks it) | |
@override | |
Widget build(BuildContext context) { | |
print(view); | |
return Scaffold( | |
body: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
mainAxisSize: MainAxisSize.max, | |
children: [ | |
AnimatedSwitcher( | |
transitionBuilder: (child, animation) => | |
transitionBuilder(animation, child, view, previousView), | |
duration: Duration(milliseconds: 200), | |
child: IndexedStack( | |
key: ValueKey<int>(view), | |
index: view, | |
children: [ | |
this.widget.registerPage, | |
this.widget.loginPage, | |
this.widget.resetScreen, | |
], | |
), | |
), | |
ButtonBar( | |
children: [ | |
ElevatedButton( | |
child: Text("Back"), | |
onPressed: () { | |
if (view == 0) return null; | |
setState(() { | |
previousView = view; | |
view -= 1; | |
}); | |
}, | |
), | |
ElevatedButton( | |
child: Text("Continue"), | |
onPressed: () { | |
if (view == 2) return null; | |
setState(() { | |
previousView = view; | |
view += 1; | |
}); | |
}, | |
) | |
], | |
) | |
], | |
), | |
); | |
} | |
} | |
SlideTransition transitionBuilder( | |
Animation<double> animation, Widget child, int view, int previousView) { | |
final fromLeft = | |
Tween<Offset>(begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0)) | |
.animate(animation); | |
final fromRight = | |
Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)) | |
.animate(animation); | |
bool goingIn = (child.key == ValueKey(view)); | |
bool goingBack = (view < previousView); | |
return SlideTransition( | |
child: Padding( | |
padding: const EdgeInsets.symmetric(horizontal: 16.0), | |
child: child, | |
), | |
position: (goingIn && !goingBack || !goingIn && goingBack) | |
? fromRight | |
: fromLeft); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment