Skip to content

Instantly share code, notes, and snippets.

@WesselvanDam
Last active February 27, 2021 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WesselvanDam/df423bb0ad190743bd7ee13820213489 to your computer and use it in GitHub Desktop.
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.
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