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.