Tag: Flutter

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

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: ...
);

GitLab CI + Flutter: pub: command not found

In one of my projects, I used a GitLab environment to perform Flutter tests. For this, I setup my .gitlab-ci.yaml to use a Flutter docker image of cirrusci/flutter for code quality check or tests. The file looks like this:

code_quality:
  stage: test
  image: "cirrusci/flutter:stable"
  tags:
    - docker
  before_script:
    - pub global activate dart_code_metrics
    - export PATH="$PATH":"$HOME/.pub-cache/bin"
  script:
    - metrics lib -r codeclimate  > gl-code-quality-report.json
      
# [...]

test:
  stage: test
  image: "cirrusci/flutter:stable"
  tags:
    - docker
  before_script:
    - pub global activate junitreport
    - export PATH="$PATH":"$HOME/.pub-cache/bin"
  script:
    - flutter test --machine --coverage | tojunit -o report.xml
    - lcov --summary coverage/lcov.info
    - genhtml coverage/lcov.info --output=coverage

# [...]

Up to version 2.10.* of the Flutter docker image, this worked fine. But starting with version 3.0.0, there seems to be some changes in the binaries or their paths. The scripts failed with an error:

/usr/bin/bash: line 123: pub: command not found

To fix this error, the pub commands need to be adjusted and set to flutter pub:

# [...]

  before_script:
    - flutter pub global activate dart_code_metrics

# [...]

  before_script:
    - flutter pub global activate junitreport

# [...]

This fixed the issue and all tests finished successfully.

Build and Release a Flutter App

Updating the app’s version number

To update the version number, navigate to the pubspec.yaml file and update the following line with the current version string:

version: 1.0.0+1

After the change, run:

flutter pub get

Build and release the iOS app

A detailled description of the whole process is described at docs.flutter.dev.

To release the iOS app, you use Flutter to build a xcarchive file. This build archive can be published the same way you would do it with Xcode by using the archive manager and one of the different Distribution options.

Build the iOS app:

flutter build ipa

The generated xcarchive file is saved to your app directory under:

/build/ios/archive/MyApp.xcarchive

Build and release the Android app

A detailled description of the whole process is described at docs.flutter.dev.

To release the Android app, you use Flutter to build a app bundle aab file. This file can be distributed by using Google Play Console or any other store.

Build the Android app:

flutter build appbundle

The generated aab app bundle file is saved to your app directory under:

/build/app/outputs/bundle/release/MyApp.aab

Photo by Artur Shamsutdinov on Unsplash

Flutter: rounded corners for images

There are different possibilities to create a rounded corner of images:

BoxDecoration

To create a rounded corner image in Flutter, you can use the Container widget and set the decoration property to a BoxDecoration with a borderRadius that defines the rounded corners. Here’s an example:

Container(
  height: 100.0,
  width: 100.0,
  decoration: BoxDecoration(
    image: DecorationImage(
      fit: BoxFit.cover, 
      image: NetworkImage('https://example.com/image.jpg'),
    ),
    borderRadius: BorderRadius.circular(10.0),
  ),
),

In this example, the width and height properties of the Container define the size of the image, the DecorationImage property defines the image source and how it should be scaled to fit the container and the borderRadius property is used to create the rounded corners with a Radius.circular(10).

ClipRRect

You can also use ClipRRect widget to create rounded corner Image in flutter.

ClipRRect(
  borderRadius: BorderRadius.circular(10.0),
  child: Image.network(
    'https://example.com/image.jpg',
    height: 100.0,
    width: 100.0,
    fit: BoxFit.cover,
  ),
),

You can adjust the radius value as per your need.

Photo by Chaitanya Tvs on Unsplash

Flutter: enable scroll-to-top for nested Scaffolds (e.g. in IndexedStack)

When using nested Scaffolds (e.g. in combination with IndexedStack), the PrimaryScrollController is not usable by default. An IndexedStack will load all subviews so scroll-to-top will change all scrollable views at the same time, even if they are not visible or it simply does not work, because the PrimaryScrollController can only be attached to a single Scaffold.

To overcome this issue, the scrolls_to_top package can be used. This also works for nested Scaffolds. The functionality of the package is described in this post (here is the english translation).

The following code example shows the usage. This is how to use ScrollsToTop within each children of IndexedStack:

  final _scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      primary: true,
      body: ScrollsToTop(
        onScrollsToTop: (event) {
          // onScrollsToTop will be called on each touch event, so check if the view is currently visible
          if (!widget.isOnScreen) return;

          _scrollController.animateTo(
            event.to,
            duration: event.duration,
            curve: event.curve,
          );
        },
        child: ListView.builder(
          itemBuilder: _itemBuilder,
          itemCount: 100,
          controller: _scrollController,
        ),
      ),
    );
  }

Flutter: add drag handle to ReorderableListView

By default, ReorderableListView only shows drag handles on desktop (GitHub). To enable a drag handle inside a ReorderableListView, it is possible to add the following code into the child’s subtree:

ReorderableDragStartListener(
  index: index,
  child: const Icon(Icons.drag_handle),
),

A full example usage with a very simple list:

var moviesTitles = ['Inception', 'Heat', 'Spider Man'];

ReorderableListView(
  onReorder: (oldIndex, newIndex) {
    // Handle reorder
  },
  children: moviesTitles.map((movie) {
    var index = moviesTitles.indexOf(movie);
    return ListTile(
      key: Key('${index}'),
      tileColor: Colors.white,
      title: Text(movie),
      trailing: ReorderableDragStartListener(
        index: index,
        child: const Icon(Icons.drag_handle),
      ),
      onTap: () {
        // Handle tap
      },
    );
  }).toList(),
);

This will result in the following output: