skip to Main Content

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


  1. You have to wrap your textField with the SizedBox to fix the size:

    SizedBox(
    width: 250,
    child: TextField()
    )
    
    Login or Signup to reply.
  2. 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

    SizedBox(
    width: 70,
    child: YourTF()
    )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search