13

Today I came over following snippet of code that implements gradient in flutter

return new Container(
  ...
  decoration: new BoxDecoration(
    gradient: new LinearGradient(
      colors: [
        const Color(0xFF3366FF), 
        const Color(0xFF00CCFF),
      ]
      begin: const FractionalOffset(0.0, 0.0),
      end: const FractionalOffset(1.0, 0.0),
      stops: [0.0, 1.0],
      tileMode: TileMode.clamp
    ),
  ),
),

And it raised 2 questions:

1) What color system is 0xFF3366FF this? it looks somewhat similar to HEX, but it isn't.

2) Why do we use const for const Color() opposed to new Color() I understand different between both, but const here feels unintuitive for me, I'd expect it to be creating a new Color() class instance, similarly to how we use new Text("Some text"). If it needs to be const, why isn't TileMode.clamp also a const?

Ilja
  • 44,142
  • 92
  • 275
  • 498

3 Answers3

16

From the Flutter source

class Color {
  /// Construct a color from the lower 32 bits of an [int].
  ///
  /// The bits are interpreted as follows:
  ///
  /// * Bits 24-31 are the alpha value.
  /// * Bits 16-23 are the red value.
  /// * Bits 8-15 are the green value.
  /// * Bits 0-7 are the blue value.
  ///
  /// In other words, if AA is the alpha value in hex, RR the red value in hex,
  /// GG the green value in hex, and BB the blue value in hex, a color can be
  /// expressed as `const Color(0xAARRGGBB)`.
  ///
  /// For example, to get a fully opaque orange, you would use `const
  /// Color(0xFFFF9000)` (`FF` for the alpha, `FF` for the red, `90` for the
  /// green, and `00` for the blue).
  const Color(int value) : value = value & 0xFFFFFFFF;

const instances are canonicalized.

If you have multiple const Color(0xFF00CCFF) in your code, only one instance will be created.

const instances are evaluated at compile time. In the Dart VM this is when the code is loaded, but in Flutter production AoT compilation is used and const values therefore provide a small performance benefit.

See also How does the const constructor actually work?

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    The performance gain is not that minimal. Because it allows to use `const` constructor on widgets too ; which will lead to a shortcut in the tree rendering. – Rémi Rousselet Dec 27 '17 at 20:18
  • @Darky perhaps. Guessing possible performance gains is difficult. Only benchmarks for concerete use cases are reliable. – Günter Zöchbauer Dec 27 '17 at 20:31
  • 5
    Yeah but in this case, it's the flutter team that recommend const widgets for this exact purpose. Because it will skip the `build` method call. Also : https://youtu.be/dkyY9WCGMi0?t=30m59s – Rémi Rousselet Dec 27 '17 at 21:02
15

As explained by the accepted answer, const constructors are a small optimization.

In dart a const MyObject(42) will only be allocated once even when you call it hundreds of time. Which means less memory allocation > faster


But isn't it a negligible optimization ?

Well, from dart point of view, yes. But we're in flutter here. We also have a Widget tree that can also use const constructors. Which means that we could change your code example to something like this :

return const DecoratedBox(
  decoration: const BoxDecoration(
    gradient: const LinearGradient(
      colors: const [
        const Color(0xFF3366FF), 
        const Color(0xFF00CCFF),
      ],
      begin: const FractionalOffset(0.0, 0.0),
      end: const FractionalOffset(1.0, 0.0),
      stops: const [0.0, 1.0],
      tileMode: TileMode.clamp
    ),
  ),
);

Here, thanks to Color being a constant, we managed to get a constant LinearGradient, and ultimately a constant DecoratedBox widget. So not only will the DecoratedBox widget be instantiated only once ; but thanks to widgets being immutable ; Flutter will recognize that the widget is the same.

Consequence :

  • The whole sub-tree of DecoratedBox will be built once.
  • The associated RenderObject (RenderDecoratedBox in this case) will be not be updated at all even when it's parent Container change

This is explained in "Flutter's layered design" video talk. At 31mn to be exact. But I'd suggest to start the video from here to have a bigger understanding of what's skipped.

PS : Some widgets don't have a const constructor at all. Such as Container. But in the case of Container you could simply use a DecoratedBox instead, which is basically what Container use under the hood. The advantage here is that DecoratedBox do have a const constructor.

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • This is awesome information, thank you for the links, will definitely give this a look now! Things like these are what I missed from being mostly in JavaScript environment, it takes out so much knowledge out :/ – Ilja Dec 28 '17 at 10:27
0
import 'package:flutter/material.dart';

class AppColors {
  static const Color kTransparent = Colors.transparent;
  static const Color kWhite = Colors.white;
  static const Color kBlack = Colors.black;
  static const Color kRed = Colors.red;
  static const Color kRedA = Colors.redAccent;
  static const Color kPink = Colors.pink;
  static const Color kPinkA = Colors.pinkAccent;
  static const Color kBlue = Colors.blue;
  static const Color kBlueA = Colors.blueAccent;
  static const Color kLightBlue = Colors.lightBlue;
  static const Color kLightBlueA = Colors.lightBlueAccent;
  static const Color kGreen = Colors.green;
  static const Color kGreenA = Colors.greenAccent;
  static const Color kLightGreen = Colors.lightGreen;
  static const Color kLightGreenA = Colors.lightGreenAccent;
  static const Color kLime = Colors.lime;
  static const Color kLimeA = Colors.limeAccent;
  static const Color kGrey = Colors.grey;
  static const Color kBlueGrey = Colors.blueGrey;
  static const Color kPurple = Colors.purple;
  static const Color kPurpleA = Colors.purpleAccent;
  static const Color kDeepPurple = Colors.deepPurple;
  static const Color kDeepPurpleA = Colors.deepPurpleAccent;
  static const Color kIndigo = Colors.indigo;
  static const Color kIndigoA = Colors.indigoAccent;
  static const Color kYellow = Colors.yellow;
  static const Color kYellowA = Colors.yellowAccent;
  static const Color kOrange = Colors.orange;
  static const Color kOrangeA = Colors.orangeAccent;
  static const Color kDeepOrange = Colors.deepOrange;
  static const Color kDeepOrangeA = Colors.deepOrangeAccent;
  static const Color kAmber = Colors.amber;
  static const Color kAmberA = Colors.amberAccent;
  static const Color kCyan = Colors.cyan;
  static const Color kCyanA = Colors.cyanAccent;
  static const Color kTeal = Colors.teal;
  static const Color kTealA = Colors.tealAccent;
  static const Color kBrown = Colors.brown;
}
ajaybadole
  • 121
  • 1
  • 1
  • 6