Division – Style Your Flutter Widgets Without Confusion

In Flutter, everything is a widget. You can freely compose them and create your own which is awesome! However, there are certain inconsistencies and lacking features that make styling and positioning widgets a pain. What’s more, it’s pretty tough to extract a style of a widget. What if you want to reuse just the padding and border radius on multiple different widgets? Well, you’re out of luck…

Unless you use a package called division which allows you to do just that! Extract styles and make styling an enjoyable endeavor by streamlining certain processes.

he project we will build

A hypothetical designer has designed a beautiful 😉 UI component for displaying messages to the user. It has all the bells and whistles, like ripple effectelevationround corners and the list goes on…

Good, thinking that creating a MessageDisplay widget looking precisely like the spec will be an easy task, we hop straight into implementation:

main.dart

class MessageDisplayClassic extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Text(
            'Lorem ipsum dolor sit amet...',
            style: TextStyle(
              color: Colors.white,
              fontSize: 30,
              fontWeight: FontWeight.bold,
              fontStyle: FontStyle.italic,
            ),
          ),
        ),
        width: 350,
        decoration: BoxDecoration(
          color: Colors.green.shade800,
          borderRadius: BorderRadius.circular(8),
        ),
      ),
    );
  }
}

The widget above is starting to take shape, but it lacks elevation and ripple effect (aka an InkWell), scale and also rotation. Also, we’d need to react to taps and somehow ani​​​​mate properties.

The current look of the widget

Could we do all that using the standard Flutter way of styling widgets? Sure, but look a the code above. Even now it’s looking like a mess and simply extracting all of the objects into helper methods wouldn’t help a lot.

A better way to style

The division package sets out to relieve app developers from problems and confusions like the following:

  • When you want to center a Flutter widget, you have to wrap it inside a Center widget.  Trying to add some padding? Wrap it inside a Padding widget. However, do you want to change the color of a Container, let’s say? Well, you cannot wrap it inside a Color widget… Instead you have to set the color property.
  • Do you want to set an elevation on a Container? Well, you’re out of luck! That’s only supported on material widgets, such as a Card.

As you can see, many of Division’s features will be immensely helpful in making the widget we’re building possible without any hair loss.

Using Division

Division borrows from CSS in a good way. With it, applying a padding is no different from changing the color! Just set properties on a ParentStyle object and you’re set. No more wrapping into a Padding widget or other craziness. Division also provides a TxtStyle class made specifically for styling text.

First, add division to the project:

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  division: ^0.8.2

Let’s put this package into practice and recreate the code above using Division.

main.dart

class MessageDisplayDivision extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Parent(
      child: Container(
        child: Txt(
          'Lorem ipsum dolor sit amet...',
          style: TxtStyle()
            ..textColor(Colors.white)
            ..fontSize(30)
            ..bold()
            ..italic()
            ..textAlign.start(),
        ),
      ),
      style: ParentStyle()
        ..alignment.center()
        ..padding(all: 16)
        ..width(350)
        ..background.color(Colors.green.shade800)
        ..borderRadius(all: 8),
    );
  }
}

The code above looks different from the previous one, but after you dissect it for a bit, you’ll realize just how simple it is to use Division. Define a Parent which takes in a child that you want to style (verb 😉) and obviously, provide the actual style (noun 😎).

Styling a text is very similar, just instead of the regular Text widget, use Division’s wrapper called Txt and apply a TxtStyle instead of a ParentStyle.

Also, where have all of our trusted widget friends like Center and Padding go? They are now applied on the ParentStyle, just like all of the other style-related attributes.

In addition to having all the styling readably defined in one place, we can now extract the styling and use it across multiple widgets in a manageable way! Consider how clean this code looks…

main.dart

class MessageDisplayDivisionSimple extends StatelessWidget {
  ...

  @override
  Widget build(BuildContext context) {
    return Parent(
      child: Container(
        child: Txt(
          'Lorem ipsum dolor sit amet...',
          style: textStyle,
        ),
      ),
      style: containerStyle,
    );
  }
}

…after we put the styles into variables literally with zero hassle 🎉. You know, it’s not like we have to manage the Container being wrapped inside a Center widget or anything like that 😏

You can put the styles into some global static final fields or make them local to one widget, it’s up to you.

main.dart

class MessageDisplayDivisionSimple extends StatelessWidget {
  final containerStyle = ParentStyle()
    ..alignment.center()
    ..padding(all: 16)
    ..width(350)
    ..background.color(Colors.green.shade800)
    ..borderRadius(all: 8);

  final textStyle = TxtStyle()
    ..textColor(Colors.white)
    ..fontSize(30)
    ..bold()
    ..italic()
    ..textAlign.start();

  ...
}

What we’ve accomplished with Division by now is great, but we’re just breaking even with what we had implemented using the standard Flutter way of doing things. Let’s add all the other styling goodness which would be tougher to do without Division, namely elevation, ripple effect, rotation, scaling and more!

Leave a Reply

Your email address will not be published. Required fields are marked *