Category: Flutter

FutureBuilder: handle multiple futures in a single widget

moving staircase at night

By default, FutureBuilder provides a single future parameter that handles a single Future. For multiple Futures, we can combine them into a single Future using Future.wait. Here’s a step-by-step guide on how to do this:

Create a list of Future objects

Create a list of Future objects that represent the asynchronous operations you want to perform. For example, let’s assume you have two futures:

Future<String> fetchFirstData() async {
  // Simulate a network request or other asynchronous operation.
  await Future.delayed(Duration(seconds: 2));
  return "First Data";
}

Future<int> fetchSecondData() async {
  // Simulate another asynchronous operation.
  await Future.delayed(Duration(seconds: 3));
  return 42;
}

Combine the futures using Future.wait

Use the Future.wait method to combine the individual futures into a single future. Future.wait takes a list of futures as an argument and returns a single future that completes when all the input futures have completed.

Future<void> fetchData() async {
  await Future.wait([fetchFirstData(), fetchSecondData()]);
}

Create a FutureBuilder widget

Now, use the FutureBuilder widget to handle the combined future and display the results in your widget tree. You can place this widget in your build method.

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: fetchData(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          // Use the results from the futures here.
          if (snapshot.hasError) {
            return Text("Error: ${snapshot.error}");
          } else {
            return Column(
              children: [
                Text("First Data: ${snapshot.data[0]}"),
                Text("Second Data: ${snapshot.data[1]}"),
              ],
            );
          }
        } else {
          // While waiting for the futures to complete, you can show a loading indicator or placeholder.
          return CircularProgressIndicator();
        }
      },
    );
  }
}

In the code above, we use the snapshot to check the connectionState. When the connectionState is ConnectionState.done, it means that both futures have completed. You can access the results using snapshot.data.

Remember to replace the fetchFirstData and fetchSecondData functions with your actual asynchronous operations. This example demonstrates how to use FutureBuilder to handle multiple futures in a single widget in Flutter.

Foto von Tomasz Frankowski auf Unsplash

 

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 remove the debug banner during development

By default, Flutter shows a debug banner on the top right corner of an app, that indicates that the app was build in debug mode.

This banner…

… is intended to deter people from complaining that your app is slow when it’s in debug mode. In debug mode, Flutter enables a large number of expensive diagnostics to aid in development, and so performance in debug mode is not representative of what will happen in release mode.

https://api.flutter.dev/flutter/material/MaterialApp/debugShowCheckedModeBanner.html

But sometimes you want to remove this banner because it overlaps UI elements or other view elements. To do so, you can simply remove the debug banner by setting the debugShowCheckedModeBanner property of the MaterialApp widget to false. For example:

MaterialApp(
  debugShowCheckedModeBanner: false,
  // ...
)

This will remove the banner at the top right corner that indicates the app is in debug mode.

This banner is only visible in debug mode. When you compile your app in release mode, this banner is not visible at all.

Flutter: how to create a better MaterialColor from Color

toucan

In Flutter, MaterialColor is a class that defines a color palette to be used within a Material Design app. It creates a set of shades for a given primary color, which can be used in various components of the UI, such as buttons, text fields, and navigation bars. MaterialColor objects can be created from a single color value and then generate shades based on a specified brightness factor. This allows for a consistent and harmonious color scheme throughout the app.

To create a MaterialColor from a Color, you can use the MaterialColor class in Dart. The MaterialColor constructor takes two arguments:

  • The value of the color in RGB.
  • A map of shades of the color with keys representing the shade level and values representing the Color of that shade.

Let’s say we want to create a MaterialColor from the RGB color 176 / 255 / 38:

To use an implementation, let’s create a static method in a MaterialColorGenerator class and call:

Color color = Color.fromARGB(255, 176, 255, 38);
MaterialColor material = MaterialColorGenerator.from(color);

Now there are different ways to define the shades. Most tutorials propose to change the opacity for each shade, which will result in such a code:

import 'package:flutter/material.dart';

class MaterialColorGenerator{
  static MaterialColor from(Color color) {
    return MaterialColor(color.value, <int, Color>{
      50: color.withOpacity(0.1),
      100: color.withOpacity(0.2),
      200: color.withOpacity(0.3),
      300: color.withOpacity(0.4),
      400: color.withOpacity(0.5),
      500: color.withOpacity(0.6),
      600: color.withOpacity(0.7),
      700: color.withOpacity(0.8),
      800: color.withOpacity(0.9),
      900: color.withOpacity(1.0),
    });
  }
}

Let’s take our color example and look at the result:

Color values from shade50 (top) to shade900 (bottom).

This is a good result for lighter colors, but results in very similar colors for the “darker” shades. To create some real color variations, it’s better to adjust the color values itself by using:

import 'package:flutter/material.dart';

class MaterialColorGenerator{
  static MaterialColor from(Color color) {
    List strengths = <double>[.05];
    final swatch = <int, Color>{};
    final int r = color.red, g = color.green, b = color.blue;

    for (int i = 1; i < 10; i++) {
      strengths.add(0.1 * i);
    }
    for (var strength in strengths) {
      final double 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(color.value, swatch);
  }
}

Let’s take our color example and look at the result:

Color values from shade50 (top) to shade900 (bottom).

Now the result is good for “darker” shades (> 500), but there is less variation for the “lighter” colors. Let’s find a version that combines both of the advantages:

import 'dart:math';
import 'package:flutter/material.dart';

class MaterialColorGenerator{
  static MaterialColor from(Color color) {
    return MaterialColor(color.value, {
      50: tintColor(color, 0.9),
      100: tintColor(color, 0.8),
      200: tintColor(color, 0.6),
      300: tintColor(color, 0.4),
      400: tintColor(color, 0.2),
      500: color,
      600: shadeColor(color, 0.1),
      700: shadeColor(color, 0.2),
      800: shadeColor(color, 0.3),
      900: shadeColor(color, 0.4),
    });
  }

  static int tintValue(int value, double factor) =>
      max(0, min((value + ((255 - value) * factor)).round(), 255));

  static Color tintColor(Color color, double factor) => Color.fromRGBO(
      tintValue(color.red, factor),
      tintValue(color.green, factor),
      tintValue(color.blue, factor),
      1);

  static int shadeValue(int value, double factor) =>
      max(0, min(value - (value * factor).round(), 255));

  static Color shadeColor(Color color, double factor) => Color.fromRGBO(
      shadeValue(color.red, factor),
      shadeValue(color.green, factor),
      shadeValue(color.blue, factor),
      1);
}

Let’s take our color example and look at the result:

Color values from shade50 (top) to shade900 (bottom).

This is a much better result, which corelates with the color palettes of the Material Design. This implementation is also used by the material_color_generator package.

Foto von Zden?k Machá?ek 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.

Flutter: slowing down animation for debugging

street sign "slow down"

The library that is responsible for different scheduling is flutter/scheduler. This also includes animations. To use the library, simply import package:flutter/scheduler.dart – in this case, timeDilation is all that you need.

Now you can set the variable timeDilation to a custom double. The value 1.0 is the default animation speed. Setting it to 2.0 will slow down all animations by a factor of two.

import 'package:flutter/scheduler.dart' show timeDilation;

// ...

timeDilation = 2.0; // Slow down animations by factor two

As timeDilation is a global variable, you can set it anywhere in the code, e.g. in main():

import 'package:flutter/scheduler.dart' show timeDilation;

void main() {
  timeDilation = 3.0;
  runApp(new MyApp());
}

Photo by LOGAN WEAVER | @LGNWVR on Unsplash

Flutter: red text and yellow lines in Text widget

When using a text widget, there are some configurations where the text turns red and gets yellow lines. In my case, it looks like in the following image.

The reason for this is a lack of style parameters from the parent widget. The red text shows that there is no color information available. The yellow lines show that text decoration is missing.

In my case, I have a simple text widget in a Row:

Container(
  // ...
  child: Row(
    children: [
      // ...
      Text('External device'),
    ],
  ),
);

To solve the issue, there are different possibilities.

Provide a DefaultTextStyle

DefaultTextStyle(
  style: Theme.of(context).textTheme.bodyText1,
  child: Text('External device'),
),

Use Material

Material(
  color: Colors.transparent,
  child: Text('External device'),
),

Use style parameter of Text

Text(
  'External device',
  style: TextStyle(
    decoration: TextDecoration.none,
    color: Colors.black,
  ),
),

In this case, decoration will remove the yellow lines and color will remove the red text color.

Use Scaffold

A solution discussed in different threads might also be using a Scaffold for the parent widget. But this did not work in case.

Scaffold(
  body: Container(
    // ...
    child: ...
);