I am new to Flutter, coming from React and Vue.
I’m trying to make a simple widget used to enter hours and minutes. I think it is turning out fine, although I have the problem that the widget stretches out to take all available space. Since there is a maximum input length of two characters in each TextField
, I don’t want it to take the full width. I need only the necessary width.
However, I prefer not to set an explicit width. I would rather have the constraints simply passed down, and my widget to use only what it needs.
What class/widget is there for this purpose? Apparently not Flexible
. I tried Alignment
too but that didn’t combine well with the InputDecorator…
import 'package:flutter/material.dart';
class DurationPicker extends StatefulWidget {
const DurationPicker({super.key});
@override
_DurationPickerState createState() => _DurationPickerState();
}
const zwsp = 'u200b';
const zwspEditingValue = TextEditingValue(text: zwsp, selection: TextSelection(baseOffset: 1, extentOffset: 1));
class _DurationPickerState extends State<DurationPicker> {
List<String> input = ['', ''];
late List<TextEditingController> controllers;
late List<FocusNode> focusNodes;
int hourIndex = 0;
int minuteIndex = 1;
_DurationPickerState() {
controllers = List.generate(2, (index) => TextEditingController());
controllers.forEach((controller) {
controller.value = zwspEditingValue;
});
focusNodes = List.generate(2, (index) => FocusNode());
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
focusNodes[0].requestFocus();
});
}
@override
void dispose() {
super.dispose();
focusNodes.forEach((focusNode) {
focusNode.dispose();
});
controllers.forEach((controller) {
controller.dispose();
});
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.access_time),
const SizedBox(width: 10),
Flexible(
child: InputDecorator(
decoration: const InputDecoration(
labelText: 'Label',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10))
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: TextField(
expands: false,
controller: controllers[hourIndex],
focusNode: focusNodes[hourIndex],
maxLength: 3,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
counterText: '',
),
onChanged: (value) {
if (value.length > 2) {
focusNodes[minuteIndex].requestFocus();
} else if (value.length < 2) {
controllers[hourIndex].value = zwspEditingValue;
}
input[hourIndex] = value.replaceAll(zwsp, '');
},
),
),
const Text(':'),
Flexible(
child: TextField(
expands: false,
controller: controllers[minuteIndex],
focusNode: focusNodes[minuteIndex],
maxLength: 3,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
counterText: '',
),
onChanged: (value) {
if (value.length > 2) {
FocusScope.of(context).unfocus();
} else if (value.length < 2) {
controllers[minuteIndex].value = zwspEditingValue;
focusNodes[hourIndex].requestFocus();
}
input[minuteIndex] = value.replaceAll(zwsp, '');
},
),
),
],
),
),
),
],
);
}
}
If I get no answer, to make the scope of the question smaller: is my problem caused by the TextFields themselves, or by some parent?
2
Answers
You have to wrap your
textField
with theSizedBox
to fix the size:TextField
and many other widgets are designed to fill the available space, they have a reason and a purpose to achieve (responsiveness).you have said ‘widget takes only the necessary width‘ this is a
Flexible
.as long as you only have to enter minutes or hours 2 chars, your TextField should have a fixed size.
wrap it with
SizedBox