Under which circumstances textAlign property works in Flutter?

Dims picture Dims · Aug 1, 2018 · Viewed 108.2k times · Source

In the code below, textAlign property doesn't work. If you remove DefaultTextStyle wrapper which is several levels above, textAlign starts to work.

Why and how to ensure it is always working?

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new DefaultTextStyle(style: new TextStyle(fontSize: 10.0), child: new Column(children: <Widget>[
        new Text("Should be left", textAlign: TextAlign.left,),
        new Text("Should be right", textAlign: TextAlign.right,)
      ],))
    );
  }
}

Both approaches, suggested by Remi apparently don't work "in the wild". Here is an example I nested both inside rows and columns. First approach doesn't do align and second approach makes application just crash:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new Directionality(textDirection: TextDirection.ltr, child: new DefaultTextStyle(
            style: new TextStyle(fontSize: 10.0, color: Colors.white),
            child: new Column(children: <Widget>[
              new Row(children: <Widget>[
                new Container(color: Colors.grey, child: new Column(children: <Widget>[
                  new Align(alignment: Alignment.centerLeft, child: new Text("left")),
                  new Align(alignment: Alignment.centerRight, child: new Text("right")),
                ],)),
                new Container(color: Colors.grey, child: new Column(children: <Widget>[
                  new Align(alignment: Alignment.centerLeft, child: new Text("left")),
                  new Align(alignment: Alignment.centerRight, child: new Text("right")),
                ],)),
              ],),
              /*new Row(children: <Widget>[
                new Container(color: Colors.grey, child: new Column(children: <Widget>[
                  new SizedBox(width: double.infinity, child: new Text("left", textAlign: TextAlign.left,)),
                  new SizedBox(width: double.infinity, child: new Text("right", textAlign: TextAlign.right)),
                ],)),
                new Container(color: Colors.grey, child: new Column(children: <Widget>[
                  new SizedBox(width: double.infinity, child: new Text("left", textAlign: TextAlign.left)),
                  new SizedBox(width: double.infinity, child: new Text("right", textAlign: TextAlign.right)),
                ],)),
              ],)*/]
    )));
  }
}

What I get from code is

enter image description here

i.e. text is centered, ignoring alignment of Align element.

Answer

R&#233;mi Rousselet picture Rémi Rousselet · Aug 1, 2018

DefaultTextStyle is unrelated to the problem. Removing it simply uses the default style, which is far bigger than the one you used so it hides the problem.


textAlign aligns the text in the space occupied by Text when that occupied space is bigger than the actual content.

The thing is, inside a Column, your Text takes the bare minimum space. It is then the Column that aligns its children using crossAxisAlignment which defaults to center.

An easy way to catch such behavior is by wrapping your texts like this :

Container(
   color: Colors.red,
   child: Text(...)
)

Which using the code you provided, render the following :

enter image description here

The problem suddenly becomes obvious: Text don't take the whole Column width.


You now have a few solutions.

You can wrap your Text into an Align to mimic textAlign behavior

Column(
  children: <Widget>[
    Align(
      alignment: Alignment.centerLeft,
      child: Container(
        color: Colors.red,
        child: Text(
          "Should be left",
        ),
      ),
    ),
  ],
)

Which will render the following :

enter image description here

or you can force your Text to fill the Column width.

Either by specifying crossAxisAlignment: CrossAxisAlignment.stretch on Column, or by using SizedBox with an infinite width.

Column(
  children: <Widget>[
    SizedBox(
      width: double.infinity,
      child: Container(
        color: Colors.red,
        child: Text(
          "Should be left",
          textAlign: TextAlign.left,
        ),
      ),
    ),
  ],
),

which renders the following:

enter image description here

In that example, it is TextAlign that placed the text to the left.