Part 2: Dart Basics for Flutter

This entry is part 3 of 8 in the series Flutter Development Tutorial (Beginner to Intermediate)

4. Introduction to Dart Programming (Deeper Dive)

Variables, Data Types, and Keywords

var: Can be reassigned, but Dart infers the type based on the initial value.

var name = 'John'; // Dart infers this as a String.
name = 'Doe'; // Valid because var allows reassignment.

final: Cannot be reassigned after initialization but is not a compile-time constant.
dart.

final age = 25; 
// age = 26; // This will throw an error.

const: Like final, but it must be a compile-time constant (i.e., known when the program starts).

const pi = 3.14;
// pi = 3.1415; // Compile-time error

Note: Always use const for values that never change and should be evaluated at compile-time for optimization.

Nullable vs. Non-nullable Variables (Dart 2.12+)

By default, variables in Dart are non-nullable. You must explicitly allow them to be nullable by adding ?.

String? nullableName; // Can be null
nullableName = null; // Valid

String nonNullableName = 'John'; 
// nonNullableName = null; // Error: null is not allowed

Collections (List, Set, Map)

  • List: A list is an ordered collection of items. It can be fixed-length or growable.
List<int> numbers = [1, 2, 3];
numbers.add(4); // Growable list allows adding elements
  • Set: A Set is an unordered collection of unique items.
Set<String> uniqueNames = {'John', 'Jane', 'John'}; // Only {'John', 'Jane'}
  • Map: A Map is a collection of key-value pairs.
Map<String, String> capitals = {
  'USA': 'Washington, D.C.',
  'France': 'Paris',
};

Higher-order Functions

Functions can be passed as arguments, returned by other functions, and assigned to variables.

void execute(Function action) {
  action();
}

void sayHello() {
  print('Hello!');
}

void main() {
  execute(sayHello); // Pass function as argument
}

5. Understanding the main() Function and App Structure (Deeper Dive)

The main() Function

The main() function is the entry point of every Dart and Flutter app. Let’s break down its components:

  • main(): Starts your app. You can perform any initialization here.
  • runApp(): Instructs Flutter to display the provided widget (usually a MaterialApp or CupertinoApp).
  • MyApp class: A custom widget, often a stateless widget at the root of your app.
void main() {
  runApp(MyApp()); // Starts the Flutter app by running MyApp
}

The Widget Tree

Flutter builds a widget tree where every visual element (button, text, image) is a widget. The root widget is passed to runApp().

Let’s take a more detailed look at a typical app:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('App Title'),
        ),
        body: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Hello, Flutter!'),
    );
  }
}
  • MaterialApp: The app shell that provides navigation and themes.
  • Scaffold: Provides basic structure like AppBar, Body, and FloatingActionButton.
  • MyHomePage: Custom widget containing the app’s content.

Related posts<< Part 1: Introduction to Flutter and Environment SetupPart 3: Understanding Widgets and Building UI >>