Search code examples
flutterflutter-layout

How to align Flutter widgets in Tablecells/Tablerow when using SizedBox to manage row height?


I have Form with Text and TextFormFields in TableRows to capture some user data. Some of the rows are empty depending on the type of data being entered and so I have used SizedBoxes to maintain a fixed height for all rows so that the 'Save' button at the bottom of the form doesn't move about when showing filled/blank rows (this seemed to be the recommended approach based on an internet search).

Before I added the SizedBox widgets, the Text and TextFormFields were aligned nicely by defaultVerticalAlignment: TableCellVerticalAlignment.middle at the Table level. Now that I have added the SizedBox widgets I can't see now how to align these items.

I have searched online, but can't find an answer to this question. The Flutter guidance on TableRow says that, "The alignment of individual cells in a row can be controlled using a TableCell", but I can't see any guidance on how this is achieved. I have tried using TableCellVerticalAlignment, but that doesn't appear to have the desired effect.

Does anyone know how to get these fields to align so that the text in Text widget and text in TextFormField are aligned as per the "Without SizedBox" screen shot below?

Code snippet and screen shots below showing without and with SizedBox widgets.

Code Snippet Showing TableRow and TableCells using SizedBox...

class _InputFormState extends State<InputForm> {
  final _formKey = GlobalKey<FormState>();
  final double _height = 50;

  @override
  Widget build(BuildContext context) {
    // Build a Form widget using the _formKey created above.
    return Form(
      key: _formKey,
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(20.0),
            child: Table(
              defaultVerticalAlignment: TableCellVerticalAlignment.bottom,
              columnWidths: const {
                0: FlexColumnWidth(1.5),
                1: FlexColumnWidth(3)
              },
              children: [
                //
                // Instrument name
                //
                if (widget._record.isInstrument || widget._record.isFrequency)
                  TableRow(children: [
                    SizedBox(
                      height: _height,
                      child: const TableCell(
                        verticalAlignment: TableCellVerticalAlignment.bottom,
                        child: Text('Instrument:'),
                      ),
                    ),
                    SizedBox(
                      height: _height,
                      child: TableCell(
                        verticalAlignment: TableCellVerticalAlignment.bottom,
                        child: TextFormField(
                          initialValue: widget._record.instrument,
                          maxLines: 1,
                          inputFormatters: [
                            FilteringTextInputFormatter.allow(
                                RegExp(r'[A-Z a-z-]')),
                            LengthLimitingTextInputFormatter(35),
                          ],
                          onChanged: (value) {
                            setState(() {
                              widget._record.addInstrument = value;
                            });
                          },
                          validator: (value) {
                            if (value == null || value.isEmpty) {
                              return 'Please enter an instrument name';
                            }
                            return null;
                          },
                        ),
                      ),
                    ),
                  ]),
...

Alignment With SizedBox:

enter image description here

Alignment Without SizedBox:

enter image description here


Solution

  • I have managed to do this by wrapping the Text widget within the TableCell with an Align and setting the alignment to Alignment.CenterLeft.

    Whilst working this out, I discovered that if a Tablecell doesn't have Table (or presumably TableRow) as a parent then Flutter will thrown an error stating, "Incorrect use of ParentDataWidget Error in Flutter". More information on that error here. For me, this wasn't consistent, i.e. some runs would work fine and some runs would throw the error. To get around this problem, I have put the SizedBox and the Align widgets inside the TableCell. This works fine for me. Just wanted to flag this up as well since the advice I found, and quoted in my question, that said wrap the TableCell in a SizedBox would lead to this problem.

    Solution code snippet below:

    TableCell(
      child: SizedBox(
        height: _height,
        child: Align(
          alignment: Alignment.centerLeft,
          child: Text(_label),
        ),
      ),
    );