Tag: Dart

Dart: What is the difference between the “const” and “final” keywords?

In Dart, both const and final are used to declare variables that can’t be reassigned after they’re initialized. However, there are some differences between them:

  1. const is used to declare a compile-time constant. The value of a const variable must be known at compile time. When you create an object using const, Dart ensures that there is only one instance of that object. const can be used to create constant values of built-in types, as well as classes and collections that are also const.
  2. final is used to declare a variable that can only be set once. It doesn’t have to be initialized at compile-time, but once it’s initialized, it can’t be changed. final can be used to create non-constant values of built-in types, as well as classes and collections that are not const.

In general, use const when you have a value that will never change and you want to ensure that only one instance of it exists, and use final when you have a value that won’t change but can’t be known at compile time.

Example Usage

class MyClass {
  final int a;
  static const int b = 10;

  MyClass(this.a);

  void printValues() {
    print('a: $a');
    print('b: $b');
  }
}

void main() {
  final obj = MyClass(5);
  obj.printValues();
}

In this example, we have a class MyClass with two member variables a and b. a is declared as final, which means that it can only be assigned once, either in the constructor or when it’s declared. b is declared as static const, which means that it’s a compile-time constant and there is only one instance of it across all instances of the class.

In the constructor of MyClass, we assign the value of a. When we create an instance of MyClass in main(), we pass the value 5 to the constructor, which assigns it to a.

Then, we call the method printValues(), which prints the values of a and b. Since b is declared as static const, we can access it using the class name (MyClass.b) instead of an instance of the class.

Overall, final and const are useful in classes to create immutable values that can’t be changed once they’re initialized. final is used for values that can be initialized at runtime, while const is used for values that can be initialized at compile-time.

 

Flutter: How to Create a Color from a Hexadecimal Color String

colored pencils

In Flutter, you can create a color from a hexadecimal color string value using the Color class. The Color class takes a 32-bit integer value as an argument, where the first 8 bits represent the alpha channel (transparency) and the remaining 24 bits represent the red, green, and blue channels.

To create a color object from a hexadecimal color string value, you need to pass the value to the Color() constructor. For example, to create the color red, you can use the following code:

Color color = Color(0xFFFF0000);

To create a color from a hexadecimal string value, you need to convert the string to a 32-bit integer value first. Here’s an example of how to do it:

String hexColor = "#FF0000"; // red color
Color color = Color(int.parse(hexColor.substring(1, 7), radix: 16) + 0xFF000000);

In the above code, the substring(1, 7) method is used to remove the “#” character from the hexadecimal color string. The int.parse() method converts the remaining string into a 32-bit integer value using the radix argument, which specifies that the string is in base 16 (hexadecimal). The + 0xFF000000 part adds the alpha channel value of 255 (fully opaque) to the color value.

Colors with Transparency

You can also create colors with transparency using an eight-digit hexadecimal color string value. The first two digits represent the alpha channel, which controls the opacity of the color. For example, to create a semi-transparent red color, you can use the following code:

Color semiTransparentColor = Color(0x80FF0000);

Or for a given string value:

String hexColor = "#FF0000"; // red color
Color semiTransparentColor = Color(int.parse(hexColor.substring(1, 7), radix: 16) + 0x80000000);

Here, 0x80FF0000 is the hexadecimal color value for red with 50% transparency. The first two digits “80” represent the alpha channel, and the remaining six digits represent the color components.

Usage in Widgets

You can now use the color object to set the color of any widget in your Flutter application:

Container(
  color: color,
  child: ...
)

You can also use the color object as a parameter in some widgets, such as the IconButton widget. Here’s an example:

IconButton(
  icon: Icon(Icons.add),
  color: color, 
  onPressed: () {}, 
)

Foto von Ramakant Sharda auf Unsplash

 

Flutter: how to sort a list of objects by one of its properties

In Flutter (Dart), you can use the sort method on a list of objects, along with a custom comparator function, to sort the list by the alphabetical order of one of its properties.

Here’s an example of how you can sort a list of objects (let’s say they’re called Person) by their name property:

List<Person> people = [
  Person(name: "Bob"),
  Person(name: "Charlie"),
  Person(name: "Alice"),
];

people.sort((a, b) => a.name.compareTo(b.name));

In this example, the sort method takes a comparator function as its argument. The comparator function compares two Person objects and returns a negative, zero, or positive value, depending on whether the first object should be sorted before, in the same position as, or after the second object. In this case, it compares the name property of each object using the compareTo method and sorts them alphabetically.

Another way to sort by one property is to use the sortBy method from the ‘dart:collection’ package:

import 'dart:collection';

people.sortBy((person) => person.name);

This will sort the list of people based on the name property.

Dart: code snippets for faster coding

There are different concepts that improve the data handling in Dart. The following list of snippets is a collection of the most handy once. Warning: this might simplify your code a lot! 😉

The Spread Operator

Dart supports the spread operator, which allows to insert a collection (multiple elements) into a collection:

var values = [1, 2, 3];
var moreValues = [...values, 4, 5, 6];
print(moreValues);
// [1, 2, 3, 4, 5, 6]

Operators

Dart supports different operators. You can implement many of these operators as class members.

DescriptionOperator
unary postfixexpr++    expr--    ()    []    .    ?.
unary prefix-expr    !expr    ~expr    ++expr    --expr      await expr 
multiplicative*    /    %  ~/
additive+    -
shift<<    >>    >>>
bitwise AND&
bitwise XOR^
bitwise OR|
relational and type test>=    >    <=    <    as    is    is!
equality==    !=
logical AND&&
logical OR||
conditionalexpr1 ? expr2 : expr3
cascade..    ?..
assignment=    *=    /=   +=   -=   &=   ^=   etc.

Merging Two Maps

The code snippet below merges two maps. All (key) values in default are available in the merged map. This snippet only works for single level maps, multidimensional maps are only handled on the first level:

var options = {
    "hidden": "false",
    "option": "3",
};
var defaults = {
    "hidden": "true",
    "escape": "false",
};
options = {...defaults, ...options};
print(options);
// {hidden: false, escape: false, option: 3}

Default Value

To set a default value for a nullable variable, you can use the “if null” operator ‘??’:

const defaultValue = "Default";
final someVar = null;
var expectingValue = someVar ?? defaultValue;
print(expectingValue);
// "Default"

if and for in Collections

Dart offers an easy way to create dynamic lists by using conditionals (if) and repetition (for):

var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];
var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

String to Number

var stringValue = "123";
var intValue = int.parse(stringValue);
print(intValue);
// 123 (int)
var stringValue = "123.45";
var doubleValue = double.parse(stringValue);
print(doubleValue);
// 123.45 (double)

Numbers to String

Most of the Dart data types support a toString() method, which allows a conversion to strings. This is very handy for every parameter where a string is needed:

int intValue = 123;
var stringValue = intValue.toString();
print(stringValue);
// "123" (string)

Check if object exists in list

To check if an object is already in a list, you can use the .where() method. It checks and creates a list based on given conditions. So if the result is not empty then that item exists.

var list = List<MyObject>[];
var myObject = MyObject();
if (list.where((element) => element.optionId == myObject.optionId).isNotEmpty) {
  print('object exists');
} else {
  print('object does not exist');
}

Flutter on iOS: themeMode does not change to dark mode if `ThemeMode.system` is used

In my case, a simple app should automatically use the theme (light or dark) of the system to style the user interface. By default, this should work when using ThemeMode.system (see flutter documentation). But it didn’t.

The themes have been defined as follows:

    return MaterialApp(
      themeMode: ThemeMode.system,
      theme: ThemeData( ... ),
      darkTheme: ThemeData( ...),
      ...
    );

In addition, the WidgetsBindingObserver callback didChangePlatformBrightness() was never called. It was defined as follows:

class MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver
{
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangePlatformBrightness() {
    print(WidgetsBinding.instance.window.platformBrightness);
    // > should print Brightness.light / Brightness.dark when you switch
    super.didChangePlatformBrightness();
  }
}

After hours and days of searching, it turned out, that the following definition was set in info.plist of iOS:

<key>UIUserInterfaceStyle</key>
<string>Light</string>

Removing this line solved the issue. This setting sets the apps theme to Light, which results in a constant value even if the user changed the brightness to dark. Without this line, UIUserInterfaceStyle depends on the global setting.

Source: https://stackoverflow.com/questions/61620332/platform-brightness-is-still-light-on-ios-even-when-dark-mode-is-on-flutter

Flutter: generating *.g.dart files for json serialization

The full documentation for this is available on flutter.dev

When creating json_serializable classes the first time, you’ll get errors similar to what is shown in the image below.

These errors are entirely normal and are simply because the generated code for the model class does not exist yet. To resolve this, run the code generator that generates the serialization boilerplate.

There are two ways of running the code generator.

One-time code generation

By running 

flutter pub run build_runner build

in the project root, you generate JSON serialization code for your models whenever they are needed. This triggers a one-time build that goes through the source files, picks the relevant ones, and generates the necessary serialization code for them.

While this is convenient, it would be nice if you did not have to run the build manually every time you make changes in your model classes.

Generating code continuously

watcher makes our source code generation process more convenient. It watches changes in our project files and automatically builds the necessary files when needed. Start the watcher by running

flutter pub run build_runner watch

in the project root.

It is safe to start the watcher once and leave it running in the background.

Source: https://flutter.dev/docs/development/data-and-backend/json#code-generation