Categories
dart flutter software_dev

Dart extension experiment

I had a use for Dart extensions, but after playing with the code, I found I could make it more compact with an existing method.

I work with an app which utilizes colors at 10% opacity. This sounds like a great place to use an extension on the Color object.

extension ColorOpacity on Color {
  Color get opacity10 => withOpacity(0.1);
}

This works great…and I can’t help play around with the idea. Why not multiple opacity entries to show off the range of a given color.

const Color colorCoolBlue = Color(0xFF3BB2E2);

extension ColorOpacity on Color {
  Color get opacity75 => withOpacity(0.75);
  Color get opacity50 => withOpacity(0.5);
  Color get opacity25 => withOpacity(0.25);
  Color get opacity10 => withOpacity(0.1);
}

With a simple widget to show off the results.

import 'package:flutter/material.dart';
import 'package:weathersdbx/ui/ui_const.dart';

///
/// Simple screen to try out some color ideas
///
class ExpColorsWidget extends StatelessWidget {
  const ExpColorsWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Widget _constructColorSlice(Color color) => Expanded(
          child: Container(
            color: color,
          ),
        );
    Widget _constructBody() {
      return SizedBox(
        height: 200,
        child: Row(
          children: [
            _constructColorSlice(colorCoolBlue),
            _constructColorSlice(colorCoolBlue.opacity75),
            _constructColorSlice(colorCoolBlue.opacity50),
            _constructColorSlice(colorCoolBlue.opacity25),
            _constructColorSlice(colorCoolBlue.opacity10),
          ],
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        title: const Text("Colors Experiment"),
      ),
      body: _constructBody(),
    );
  }
}

Have to admit I was a bit challenged to get all the rows to have the same width without hardcoding until I found this answer on StackOverflow thanks to diegoveloper about using the Expanded widget.

The method constructBody can further be refactored to move the color row to a separate method.

Widget _constructColorRow(
  Color color, {
  double height = 200,
}) =>
    SizedBox(
      height: height,
      child: Row(
        children: [
          _constructColorSlice(color),
          _constructColorSlice(color.opacity75),
          _constructColorSlice(color.opacity50),
          _constructColorSlice(color.opacity25),
          _constructColorSlice(color.opacity10),
        ],
      ),
    );

Widget _constructBody() {
  return _constructColorRow(colorCoolBlue);
}

And if feels like the next progression of this little experiment is to allow multiple colors, and, if we can expand one way…why not both?

const colorCoolBlue = Color(0xFF3BB2E2);
const colorDeepRed = Color(0xFF940000);

Widget _constructColorRow(
  Color color) =>
    Expanded(
      child: Row(
        children: [
          _constructColorSlice(color),
          _constructColorSlice(color.opacity75),
          _constructColorSlice(color.opacity50),
          _constructColorSlice(color.opacity25),
          _constructColorSlice(color.opacity10),
        ],
      ),
    );


Widget _constructBody() => Column(
      children: [
        _constructColorRow(colorCoolBlue),
        _constructColorRow(colorDeepRed),
      ],
    );

Now the opacity extension feels restricting, the following code goes back to the Color.withOpacity method to lift this restriction.

const defaultOpacityList = [1.0, 0.75, 0.5, 0.25, 0.10];

Widget _constructColorRow(Color color,
        {opacityList = defaultOpacityList}) =>
    Expanded(
      child: Row(children: [
        ...opacityList
            .map(
              (opacity) => _constructColorSlice(color.withOpacity(opacity)),
            )
            .toList()
      ]),
    );

Finally, adding a Dart data class to define the color and its opacities, the code has even more versatility. A further step could easily take the data out of the code altogether into something like JSON for further functionality.

class ColorDef {
  final Color baseColor;
  final List<double> opacityList;

  ColorDef(this.baseColor, this.opacityList);
}

Full final screen, exp_colors_widget.dart, can be found in my blogsdbx repository.