Flutter Learning Roadmap

10 min

10 min

Sahaj Rana

Published on Oct 3, 2023

Flutter Developer Learning Roadmap: Unveiling the Power of Dart

Introduction to Dart Programming: Unveiling the Power of Dart Google's Language

If you're on the path to becoming a proficient Flutter app developer, understanding the Dart programming language is your crucial first step. Dart is not just a companion; it's the foundation upon which Flutter, the popular UI toolkit, is built. In this blog, we'll embark on a journey through Dart's essential concepts, from its history and basics to the advanced features that empower modern app development.

History & Introduction

Let's start with a quick history lesson. Dart was introduced by Google in 2011 as a language designed for web development. Over time, its capabilities expanded, making it the primary language for Flutter app development. Dart combines a concise syntax with powerful features, making it a versatile choice for creating mobile, web, and desktop applications.

Basics

Environment Setup

Before diving into code, you'll need to set up your development environment. Ensure you have Dart installed, and choose your preferred code editor.

Install Dart: First, you need to install the Dart SDK (Software Development Kit) on your computer. You can download it from the official Dart website: Dart SDK Downloads

Choose a Code Editor: You can use various code editors or IDEs for Dart development. Some popular choices include:

  • Visual Studio Code (VS Code): VS Code is a popular and free code editor that has excellent Dart support through extensions.

    • Install the "Dart" and "Flutter" extensions from the Visual Studio Code marketplace for a better Dart development experience.

  • Android Studio with Flutter Plugin: If you plan to work with Flutter (a framework for building cross-platform mobile apps using Dart), you can use Android Studio with the Flutter plugin.

  • IntelliJ IDEA with Dart Plugin: IntelliJ IDEA is another IDE that supports Dart development. Install the Dart plugin for IntelliJ IDEA.

Syntax

Dart's syntax is clean and approachable, making it easy to learn. Its C-style structure will be familiar to many developers.

Data Types

Dart language supports the following data types −

  • Numbers − It is used to represent numeric literals – Integer and Double.

  • Strings − It represents a sequence of characters. String values are specified in either single or double quotes.

  • Booleans − Dart uses the bool keyword to represent Boolean values – true and false.

  • Lists and Maps − It is used to represent a collection of objects. A simple List can be defined as below −.

    void main() {
      // Creating a List of integers
      List<int> numbers = [1, 2, 3, 4, 5];
    
      // Accessing elements of the List
      print("List elements:");
      for (var number in numbers) {
        print(number);
      }
    
      // Adding an element to the List
      numbers.add(6);
    
      // Removing an element from the List
      numbers.remove(3);
    
      print("Updated List elements:");
      for (var number in numbers) {
        print(number);
      }
    }

Output:

List elements:
1
2
3
4
5
Modified list elements:
1
2
4
5
6

Variables

Learn how to declare and use variables to store and manipulate data in your Dart programs. In Dart, you can declare variables using various data types. Here are the most commonly used data types for declaring variables in Dart:

  1. int: Used for integer values.

  2. double: Used for floating-point (decimal) values.

  3. String: Used for text or string values.

  4. bool: Used for boolean values (true or false).

  5. var: Dart can automatically infer the data type based on the assigned value.

Operators

Explore Dart's operators, from basic arithmetic to logical operators for decision-making.

Arithmetic Operators: + - * / %

Assignment Operators: = += -= *= /=

Comparison Operators: == != < > <= >=

Logical Operators: && || !

Increment and Decrement Operators: ++ --

Conditional (Ternary) Operator: ? :

Type Test Operators:

  • is (Checks if an object is of a specific type)

  • as (Type casting)

Bitwise Operators:

  • & (Bitwise AND)

  • | (Bitwise OR)

  • ^ (Bitwise XOR)

  • ~ (Bitwise NOT)

  • << (Left shift)

  • >> (Right shift)

Other Operators:

  • .. (Cascade operator)

  • ?. (Null-aware access operator)

  • ?? (Null-aware conditional operator)

  • [] (Subscript operator for accessing elements in lists and maps)

  • () (Function call operator)

  • ~/(integer division) (Integer division operator, Dart 2.2+)

These operators are fundamental for performing various operations in Dart programming.

Loops

Master loops like `for` and `while` to control the flow of your programs.

void main() {
  for (int i = 1; i <= 5; i++) {
    print(i);
  }
}

This code defines a main function and uses a for loop to iterate from 1 to 5, printing each number on each iteration. When you run this code, it will output: 1 2 3 4 5

Decision Making

Use `if`, `else`, and `switch` statements for making decisions in your code. A decision making block evaluates a condition before the instructions are executed. Dart supports If, If..else and switch statements.

void main() {
  // Example 1: If-Else Statement
  int age = 18;

  if (age >= 18) {
    print("You are an adult.");
  } else {
    print("You are not yet an adult.");
  }

  // Example 2: Switch Statement
  String day = "Monday";

  switch (day) {
    case "Monday":
      print("It's the start of the workweek.");
      break;
    case "Friday":
      print("TGIF! It's Friday.");
      break;
    default:
      print("It's a regular day.");
  }

  // Example 3: Conditional (Ternary) Operator
  bool isRaining = true;

  String weather = isRaining ? "Grab an umbrella" : "Enjoy the sunshine";
  print(weather);
}

output:

You are an adult.
It's the start of the workweek.
Grab an umbrella

Lists & Maps

Discover the power of collections with Dart's Lists and Maps, essential for managing data efficiently.

Lists in OOP with Dart:

A list is a collection of values that can be of the same or different data types. Lists in Dart are ordered, indexed, and mutable, which means you can change their contents after creation. Lists are particularly useful when you need to work with a collection of items, such as a list of numbers, strings, or objects.

class Person {
  String name;
  int age;

  Person(this.name, this.age);
}

void main() {
  List<Person> people = [
    Person('Alice', 25),
    Person('Bob', 30),
    Person('Charlie', 35),
  ];

  // Accessing elements in the list
  print(people[0].name); // Output: Alice

  // Iterating through the list
  for (var person in people) {
    print('${person.name} is ${person.age} years old.');
  }
}

Maps in OOP with Dart:

A map is a collection of key-value pairs, where each key is unique. Maps are used when you need to associate values with specific keys and retrieve those values efficiently. In OOP, maps can be used to represent associations between objects or properties.

void main() {
  Map<String, String> dictionary = {
    'apple': 'a round fruit with red or green skin and crisp flesh',
    'banana': 'a long, curved fruit with a soft, yellow skin',
    'cherry': 'a small, round, red or black fruit with a stone inside',
  };

  // Accessing values in the map
  print(dictionary['apple']); // Output: a round fruit with red or green skin and crisp flesh

  // Iterating through the map
  dictionary.forEach((word, meaning) {
    print('$word: $meaning');
  });
}

Functions

Learn how to create functions, pass arguments, and return values, laying the groundwork for modular code.
A function is a group of statements that together performs a specific task. Let us look into a simple function in Dart as shown here −

void main() {
   add(3,4);
}
void add(int a,int b) {
   int c;
   c = a+b;
   print(c);
}

Parameters (Default+Named)

Dart provides flexibility with default and named parameters, streamlining function usage.

There are two types of parameters

  1. Required Parameters

  2. Optional Parameters

Required Parameters:
Here, must pass arguments for all the parameters otherwise could not be execute the function, it will return error. Example-

void main() {
  showDetails("your_name", "your_address", "0777777777");
}

//Required parameters
void showDetails(String name, String address, String phnNumber) {
  print("your name is $name");
  print("your address is $address");
  print("your phone number is $phnNumber");
}
your name is your_name
your address is your_address
your phone number is 0777777777
Exited

Optional Parameters:

Optional parameters are divided as three types

  1. Optional positional parameters

  2. Optional named parameters

  3. Default parameters


OOP with Dart

Dart: Embracing Object-Oriented Programming

Dart, an object-oriented programming language, fully embraces the core principles of OOP, including classes, objects, inheritance, mixins, and abstract classes. With its focus on objects as real-life entities, Dart provides a robust framework for implementing key concepts like polymorphism and data hiding. The primary aim of OOP is to simplify code and enable multitasking. Dart introduces these fundamental OOP concepts:

- Class

- Object

- Inheritance

- Polymorphism

- Interfaces

- Abstract class

Here's a brief overview of these OOP concepts in Dart.

Class:

  • In Dart, a class is a blueprint for creating objects.

  • It defines the structure and behavior of objects.

  • A class encapsulates data (attributes) and methods (functions) that operate on that data.

  • Example in Dart:

    class Person {
      String name;
      int age;
      
      Person(this.name, this.age);
      
      void sayHello() {
        print('Hello, my name is $name, and I am $age years old.');
      }
    }

Object:

  • An object is an instance of a class.

  • It represents a real-world entity with attributes (properties) and behaviors (methods).

  • Objects are created from classes and can be used to store and manipulate data.

  • Example in Dart:

    var person = Person('Alice', 25); // Creating an object
    person.sayHello(); // Calling a method on the object

Inheritance:

  • Inheritance is a mechanism that allows a class (subclass or derived class) to inherit properties and methods from another class (superclass or base class).

  • It promotes code reuse and the creation of a hierarchy of related classes.

  • Example in Dart:

    class Student extends Person {
      String major;
      
      Student(String name, int age, this.major) : super(name, age);
      
      void study() {
        print('$name is studying $major.');
      }
    }

Polymorphism:

  • Polymorphism means "many forms" and is a fundamental OOP concept.

  • It allows objects of different classes to be treated as objects of a common superclass.

  • Polymorphism enables code flexibility and extensibility.

  • Example in Dart:

    void printInfo(Person person) {
      person.sayHello();
    }
    
    var person = Person('Charlie', 35);
    var student = Student('Dave', 22, 'Math');
    
    printInfo(person);  // Hello, my name is Charlie, and I am 35 years old.
    printInfo(student); // Hello, my name is Dave, and I am 22 years old.

Interfaces:

  • Dart doesn't have a specific interface keyword but achieves interface-like behavior through abstract classes and mixins.

  • Interfaces define a contract that classes must adhere to by implementing the specified methods.

  • Dart's use of interfaces is more implicit, relying on the class hierarchy.

  • Example in Dart:

    abstract class CanFly {
      void fly();
    }
    
    class Bird implements CanFly {
      void fly() {
        print('Bird is flying.');
      }
    }

Abstract Class:

  • An abstract class is a class that cannot be instantiated directly; it's meant to be subclassed.

  • It may contain abstract methods (methods without implementation) that must be implemented by its subclasses.

  • Dart uses the abstract keyword to declare abstract classes.

  • Example in Dart:

    abstract class Shape {
      double area(); // Abstract method
    }
    
    class Circle extends Shape {
      double radius;
    
      Circle(this.radius);
    
      double area() {
        return 3.14 * radius * radius;
      }
    }


Intermediate Dart

Keywords

Dart has a set of reserved keywords that serve specific purposes in the language. These keywords are crucial for defining language constructs and operations. For example, keywords like class, return, if, and for are used to define classes, control flow, and more.

void main() {
  int age = 30;
  String name = 'Alice';
  
  if (age >= 18) {
    print('$name is an adult.');
  } else {
    print('$name is a minor.');
  }
}

Null Safety

Dart's null safety features provide a way to prevent null reference errors, making your programs more reliable and reducing unexpected crashes. With null safety, you can declare variables as non-nullable, ensuring that they always contain a valid value or are explicitly marked as nullable.

String? nullableString = 'Hello, Dart!';
String nonNullableString = 'Hello, Dart!';

Getters & Setters

Getters and setters allow you to control access to the properties of a class. Getters provide read-only access to a property, while setters allow you to modify the property's value while applying custom logic.

class Rectangle {
  double width;
  double height;

  Rectangle(this.width, this.height);

  double get area => width * height;

  set area(double value) {
    if (value > 0) {
      width = value;
      height = value;
    }
  }
}

void main() {
  var rect = Rectangle(5, 4);
  print('Area: ${rect.area}');
  rect.area = 10;
  print('Updated Area: ${rect.area}');
}

Exception Handling

Exception handling in Dart allows you to gracefully handle runtime errors and prevent application crashes. You can use try-catch blocks to catch and handle exceptions, ensuring your application remains stable even when errors occur.

void main() {
  try {
    int result = 10 ~/ 0; // This will throw a 'DivisionByZeroException'
    print('Result: $result');
  } catch (e) {
    print('An error occurred: $e');
  }
}


Advanced Dart

Lambdas

Lambdas in Dart provide a concise way to create anonymous functions.

  • They are essential for functional programming and allow you to define functions without explicitly naming them.

  • Lambdas are often used for operations like mapping, filtering, and reducing collections.

  • Example:

var add = (int a, int b) => a + b;
print(add(3, 5)); // Output: 8

Higher-Order Functions

Higher-order functions are functions that take other functions as arguments or return them as results.

  • They provide a powerful way to abstract and encapsulate behavior.

  • Higher-order functions enable you to write more generic and reusable code.

  • Example:

int operate(int a, int b, int Function(int, int) operation) {
  return operation(a, b);
}

var result = operate(5, 3, (a, b) => a + b);
print(result); // Output: 8

Closures

Closures in Dart capture and retain the scope of their containing function.

  • They allow functions to maintain access to variables from the surrounding scope even after that scope has exited.

  • Closures are useful for preserving state and behavior in asynchronous operations.

  • Example:

Function makeCounter() {
  var count = 0;
  return () {
    count++;
    print(count);
  };
}

var counter = makeCounter();
counter(); // Output: 1
counter(); // Output: 2

Future

Dart's Future class is crucial for handling asynchronous programming, allowing non-blocking operations.

  • A Future represents a potential value or error that will be available at some point in the future.

  • It enables you to perform tasks concurrently without blocking the main thread.

  • Example:

Future<int> fetchUserData() async {
  await Future.delayed(Duration(seconds: 2)); // Simulate async operation
  return 42;
}

fetchUserData().then((value) {
  print('User data: $value');
});

Streams

Streams in Dart are used to handle data sequences that may arrive over time, such as events or data from network requests.

  • They provide an elegant way to work with asynchronous data.

  • You can listen to and react to events as they occur in real-time.

  • Example:


    Stream<int> countStream() async* {
      for (int i = 1; i <= 5; i++) {
        await Future.delayed(Duration(seconds: 1));
        yield i;
      }
    }

Learn about streams for handling data sequences that may arrive over time.

With this comprehensive introduction to Dart, you're well on your way to becoming a proficient Flutter developer. Each concept you grasp brings you closer to mastering the art of app creation with Flutter. Stay tuned for more in-depth guides on Dart and Flutter development as you embark on this exciting journey!

Apart from this, we have written other in-detail articles on Flutter and mobile app development. You can find them below:


Top Blogs

Follow us on

Follow us on