Omatt
Omatt

Reputation: 10443

Flutter align TextFormField with maxLength

I'd like to align TextFormFields in a Row with one of them has maxLength configured. Same behavior occurs on mobile and web.

Row(
  children: [
    Expanded(
      child: TextFormField(
        maxLength: characterLimit,
      ),
    ),
    Expanded(
      child: TextFormField(),
    ),
  ]
)

Understandably, maxLength inflates the space at the bottom of the TextFormField. Its appearance beside a TextFormField without a maxLength isn't desirable due to misalignment.

TextFormField misalignment

Displaying a validator message aligns both TextFormFields.

TextFormField validator aligned

Using Align(alignment: Alignment.top) does nothing since both TextFormField has the same height even with one of them having maxLength. Using Padding(padding: EdgeInsets.only(bottom: paddingBottom)), both TextFormField will now have the same alignment by default due to the offset given by the Padding. But the misalignment appears upon displaying the validator message.

TextFormField validator misaligned

Minimal Repro

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _subscriptionFormKey = GlobalKey<FormState>();

  void _validate() {
    if (_subscriptionFormKey.currentState!.validate()) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Form(
        key: _subscriptionFormKey,
        child: Row(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  validator: (message) {
                    if (message == null || message.isEmpty) {
                      return 'Empty field';
                    }
                    return null;
                  },
                  maxLength: 300,
                ),
              ),
            ),
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  validator: (message) {
                    if (message == null || message.isEmpty) {
                      return 'Empty field';
                    }
                    return null;
                  },
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _validate,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Upvotes: 1

Views: 544

Answers (1)

KuKu
KuKu

Reputation: 7492

I implemented like below.

Added a 'crossAxisAlignment' parameter to Row widget.

enter image description here

crossAxisAlignment: CrossAxisAlignment.start,
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, @required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _subscriptionFormKey = GlobalKey<FormState>();

  void _validate() {
    if (_subscriptionFormKey.currentState.validate()) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Form(
        key: _subscriptionFormKey,
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  autovalidateMode: AutovalidateMode.always,
                  validator: (message) {
                    if (message == null || message.isEmpty) {
                      return 'Empty field';
                    }
                    return null;
                  },
                  maxLength: 300,
                ),
              ),
            ),
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  validator: (message) {
                    if (message == null || message.isEmpty) {
                      return 'Empty field';
                    }
                    return null;
                  },
                ),
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _validate,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Upvotes: 1

Related Questions