-
Notifications
You must be signed in to change notification settings - Fork 26.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using a key to avoid the problem of different Steps amounts generates another problem, that of the TextField losing focus every time something is typed. There's any solution? #112357
Comments
That's the error showed when a different amount of steps is given to the Stepper:
The workaround given was:
But this causes the behavior mentioned in this issue, and already commented on in the previous issue, but no solution was given... |
flutter doctor -v
|
@lohhans |
@darshankawar Here has a code sample who shows the behavior when UniqueKey() is used to avoid the another error mentioned...
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => BothPagesController(),
),
],
child: MaterialApp(
title: 'Flutter - Stepper bug',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SecondPage(title: 'Flutter - Stepper bug'),
),
);
}
}
class SecondPage extends StatefulWidget {
const SecondPage({super.key, required this.title});
final String title;
@override
State<SecondPage> createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
int _index = 0;
Map<String, TextEditingController> textEditingControllers = {};
Map<String, TextField> textFields = {};
late final BothPagesController controller;
var listOne = ["A", "B", "C"];
bool enableNextButton = false;
@override
void initState() {
controller = context.read<BothPagesController>();
// need to be on initState because receives diferents lists (its a form)
listOne.forEach((string) {
var aFieldController = TextEditingController(text: '');
textEditingControllers.putIfAbsent(
string,
() => aFieldController,
);
textFields.putIfAbsent(string, () {
return TextField(
controller: aFieldController,
onChanged: (value) => _validateFields,
);
});
});
super.initState();
}
// The validate with state changes makes the textfield loose focus when has UniqueKey
get _validateFields {
var isAllFilled = <bool>[];
textEditingControllers.forEach((key, value) {
isAllFilled.add(value.text.isNotEmpty);
});
if (mounted && isAllFilled.every((boolean) => boolean == true)) {
setState(() {
enableNextButton = true;
});
} else {
setState(() {
enableNextButton = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Stepper(
currentStep: _index,
onStepCancel: () {
if (_index > 0) {
setState(() {
_index -= 1;
});
}
},
onStepContinue: () {
if (_index <= 0) {
setState(() {
_index += 1;
});
}
},
onStepTapped: (int index) {
setState(() {
_index = index;
});
},
type: StepperType.horizontal,
steps: listOne
.map((string) => Step(
title: Text(string),
content: Container(
alignment: Alignment.centerLeft,
child: textFields[string],
),
))
.toList(),
key:
UniqueKey(), // need to be unique to avoid metioned previous error (workaround citted)
),
),
Flexible(
child: ElevatedButton(
// 3
onPressed: enableNextButton
? () {
print('Create');
}
: null,
child: const Text('Click Me!'),
),
),
const Text('(Enables if all textfields are filled)'),
],
),
),
);
}
}
// Example of structure used on real app
enum ControllerOfBothPagesState { idle, success, error, loading }
class BothPagesController extends ChangeNotifier {
var state = ControllerOfBothPagesState.idle;
GenericModel _genericModel = GenericModel(
listData: [],
);
GenericModel get genericModel => _genericModel;
void setExperimentRequestModel(
GenericModel genericModel,
) {
_genericModel = genericModel;
notifyListeners();
}
}
class GenericModel {
List listData;
GenericModel({required this.listData});
}
name: stepper_bug
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: '>=2.18.1 <3.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
provider: ^6.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
uses-material-design: true |
Thanks for the details @lohhans |
Yes, the same happens without
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter - Stepper bug',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SecondPage(title: 'Flutter - Stepper bug'),
);
}
}
class SecondPage extends StatefulWidget {
const SecondPage({super.key, required this.title});
final String title;
@override
State<SecondPage> createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
int _index = 0;
Map<String, TextEditingController> textEditingControllers = {};
Map<String, TextField> textFields = {};
var listOne = ["A", "B", "C"];
bool enableNextButton = false;
late GenericModel genericModel;
@override
void initState() {
genericModel = GenericModel(
listData: [],
);
// need to be on initState because receives diferents lists (its a form)
listOne.forEach((string) {
var aFieldController = TextEditingController(text: '');
textEditingControllers.putIfAbsent(
string,
() => aFieldController,
);
textFields.putIfAbsent(string, () {
return TextField(
controller: aFieldController,
onChanged: (value) => _validateFields,
);
});
});
super.initState();
}
// The validate with state changes makes the textfield loose focus when has UniqueKey
get _validateFields {
var isAllFilled = <bool>[];
textEditingControllers.forEach((key, value) {
isAllFilled.add(value.text.isNotEmpty);
});
if (mounted && isAllFilled.every((boolean) => boolean == true)) {
setState(() {
enableNextButton = true;
});
} else {
setState(() {
enableNextButton = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Stepper(
currentStep: _index,
onStepCancel: () {
if (_index > 0) {
setState(() {
_index -= 1;
});
}
},
onStepContinue: () {
if (_index <= 0) {
setState(() {
_index += 1;
});
}
},
onStepTapped: (int index) {
setState(() {
_index = index;
});
},
type: StepperType.horizontal,
steps: listOne
.map((string) => Step(
title: Text(string),
content: Container(
alignment: Alignment.centerLeft,
child: textFields[string],
),
))
.toList(),
key:
UniqueKey(), // need to be unique to avoid metioned previous error (workaround citted)
),
),
Flexible(
child: ElevatedButton(
// 3
onPressed: enableNextButton
? () {
print('Create');
}
: null,
child: const Text('Click Me!'),
),
),
const Text('(Enables if all textfields are filled)'),
],
),
),
);
}
}
class GenericModel {
List listData;
GenericModel({required this.listData});
}
|
Yes, now try to digit anything on textfield, the focus scope will unfocus the textfield, so, you can't type a word at once, like "flutter", it will be typed letter by letter instead of normal typing, try to do it and you'll see. |
Can you take a look at this and see if it helps ? |
Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. |
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
A solution is needed, because as commented in this answer, using a key to avoid the problem of different Steps amounts generates another problem, that of the TextField losing focus every time something is typed...
I used this solution for some time, there is one problem though:
If there is a input field inside a Step and you try to input data, the keyboard immediately closes, probably as the key is regenerated due to changing viewport dimensions and therefore focus to the input element is lost.
Originally posted by @janhaa in #27187 (comment)
The text was updated successfully, but these errors were encountered: