Is there a map of Material design colors for Flutter?

Viewed 29992

I have a widget that I'd ideally like to take in a base Material color and output a widget themed with shades of that color. For example:

return new Container(
  color: Colors.pink.shade50,
  child: new Text(
    'hello',
    style: new TextStyle(
      color: Colors.pink.shade100,
    ),
  ),
);

requires me to specify both shades of pink. Ideally, I could do something like:

Color color = getBaseColorForThisPage(); // returns something like Colors.pink, but on another page, it'll return something like Colors.purple
return new Container(
  color: color.shade50,
  child: new Text(
    'hello',
    style: new TextStyle(
      color: color.shade100,
    ),
  ),
);

Is there a way to return a "map" of Material colors within a color palette, instead of just a single color? When I look at the autocomplete in IntelliJ, I see that after typing Colors.pink, I'm able to specify the shade. But if I set the color to a variable, e.g. Color color = Colors.pink, I am later not able to do color.shade100 or color[100]. Thanks!

8 Answers

Sorry, I know this already has a lot of good answers but here's the naive implementation I've been using to turn any color into a material color in case anyone finds it useful:

import 'package:flutter/material.dart';

Map<int, Color> getSwatch(Color color) {
  final hslColor = HSLColor.fromColor(color);
  final lightness = hslColor.lightness;

  /// if [500] is the default color, there are at LEAST five
  /// steps below [500]. (i.e. 400, 300, 200, 100, 50.) A
  /// divisor of 5 would mean [50] is a lightness of 1.0 or
  /// a color of #ffffff. A value of six would be near white
  /// but not quite.
  final lowDivisor = 6;

  /// if [500] is the default color, there are at LEAST four
  /// steps above [500]. A divisor of 4 would mean [900] is
  /// a lightness of 0.0 or color of #000000
  final highDivisor = 5;

  final lowStep = (1.0 - lightness) / lowDivisor;
  final highStep = lightness / highDivisor;

  return {
    50: (hslColor.withLightness(lightness + (lowStep * 5))).toColor(),
    100: (hslColor.withLightness(lightness + (lowStep * 4))).toColor(),
    200: (hslColor.withLightness(lightness + (lowStep * 3))).toColor(),
    300: (hslColor.withLightness(lightness + (lowStep * 2))).toColor(),
    400: (hslColor.withLightness(lightness + lowStep)).toColor(),
    500: (hslColor.withLightness(lightness)).toColor(),
    600: (hslColor.withLightness(lightness - highStep)).toColor(),
    700: (hslColor.withLightness(lightness - (highStep * 2))).toColor(),
    800: (hslColor.withLightness(lightness - (highStep * 3))).toColor(),
    900: (hslColor.withLightness(lightness - (highStep * 4))).toColor(),
  };
}

The function just adds a relative amount of lightness both above and below your target color. Getting the final material color would be:

final materialColor = MaterialColor(color.value, getSwatch(color));

MaterialColor extends ColorSwatch which is kind of like a Map of colors. You can use ColorSwatch anywhere you could use a Color and get the 500 shade, but you can also index into it with [].

To get a List of all the primary material color swatches, use Colors.primaries.

You can create your material color just like this:

const MaterialColor primaryColorShades = MaterialColor(
  0xFF181861,
  <int, Color>{
    50: Color(0xFFA4A4BF),
    100: Color(0xFFA4A4BF),
    200: Color(0xFFA4A4BF),
    300: Color(0xFF9191B3),
    400: Color(0xFF7F7FA6),
    500: Color(0xFF181861),
    600: Color(0xFF6D6D99),
    700: Color(0xFF5B5B8D),
    800: Color(0xFF494980),
    900: Color(0xFF181861),
  },
);

We have to use a map for it:

If you want to create your own MaterialColor with specific shades you can do something like this by creating own map of color in RGBO(Red, Gree, Blue, Opacity) form:

Map<int, Color> colorMap = {
  50: Color.fromRGBO(147, 205, 72, .1),
  100: Color.fromRGBO(147, 205, 72, .2),
  200: Color.fromRGBO(147, 205, 72, .3),
  300: Color.fromRGBO(147, 205, 72, .4),
  400: Color.fromRGBO(147, 205, 72, .5),
  500: Color.fromRGBO(147, 205, 72, .6),
  600: Color.fromRGBO(147, 205, 72, .7),
  700: Color.fromRGBO(147, 205, 72, .8),
  800: Color.fromRGBO(147, 205, 72, .9),
  900: Color.fromRGBO(147, 205, 72, 1),
};
// Green color code: 93cd48 and first two characters (FF) are alpha values (transparency)
MaterialColor customColor = MaterialColor(0xFF93cd48, colorMap); 

If you have color code value like 93cd48 then for converting it to RGB value use https://www.rapidtables.com/convert/color/hex-to-rgb.html

For more reference: https://medium.com/@jits619/flutter-material-color-conversion-ad1574f25828

https://www.youtube.com/watch?v=U19hRU9e0yw&list=PLQ7fSTYH_bV06SWG1IPnyFbavN5NB_h2o&index=7&t=345s

Why not just create your own material color instead, its easy. I also use a simple website to pick colors for flutter. Flutter Doctor Color Picker

A little late to the party, but I've made a dart extension package that is super simple to use and creates perfect MaterialColor objects. https://pub.dev/packages/material_color_gen

Super simple to use:

var newColor = Color(0xFF2929FF).toMaterialColor();

Here is an extension method I got from somewhere and I can't find where. I also had to make a small tweak to get it to work on newer, null-safe version of Dart.

extension ColorConversion on Color {
  MaterialColor toMaterialColor() {
    final List strengths = <double>[.05];
    final Map<int, Color> swatch = {};
    final r = red, g = green, b = blue;

    for (var i = 1; i < 10; i++) {
      strengths.add(0.1 * i);
    }

    for (final strength in strengths) {
      final ds = 0.5 - strength;
      swatch[(strength * 1000).round()] = Color.fromRGBO(
        r + ((ds < 0 ? r : (255 - r)) * ds).round(),
        g + ((ds < 0 ? g : (255 - g)) * ds).round(),
        b + ((ds < 0 ? b : (255 - b)) * ds).round(),
        1,
      );
    }

    return MaterialColor(value, swatch);
  }
}
Related