Understand your first Flutter project

In our last lesson, we built our very first Flutter project. It’s a simple app with just one button that increases a number every time you tap it. Below is the folder structure of this project.

Project Directory Breakdown

You’ll see a bunch of folders and files here, including android, web, windows, lib, test and more. So where do you actually write your source code? Android folder? Windows folder? Nope — it’s the lib folder. Open it up, and you’ll find a file called main.dart inside.

The lib folder will hold all your source code moving forward. You’ll write code in Dart, not Java or C++. Flutter uses the Dart programming language. Now you might wonder, why are there separate folders like android, web and windows sitting alongside lib?

The logic is straightforward. These platform folders are what let Flutter compile your single codebase into apps for every different operating system.

Flutter follows the framework concept of write one set of Dart code, run it across all platforms. The lib folder stores your shared cross-platform business logic. Meanwhile, folders such as android, windows, web, macos and linux contain native host projects for each individual platform. Their job is to embed the Flutter engine and run your Flutter app on their respective operating systems.

1. The android Folder

This is the native Android project.

It provides the runtime container for your Android app and hosts Flutter’s rendering engine. All low-level Android-specific configurations live here. Examples include app permissions, launcher icons, and application package names. This is also where you configure Android-only features and call native Android APIs — such as camera, Bluetooth, push notifications, and location services.

2. The windows Folder

This is the native project for Windows desktop applications.

It’s a raw C++ Win32 project responsible for creating native Windows windows and initializing the Skia rendering engine. Skia is Google’s graphics library that Flutter desktop relies on to draw windows and all UI controls.

All low-level Windows desktop settings are managed inside this directory: window dimensions, title bar styling, app icons, and system tray icons (the small icons shown in the bottom-right corner of Windows).

When you finish development, you can package your project as an EXE or MSIX installer and publish it to the Microsoft Store.

3. The web Folder

This folder holds a static web project built with HTML, JavaScript and CSS, and contains the main web entry file index.html. Your Dart source code gets compiled down into browser-compatible web assets here.

You configure web page titles, favicons, static assets and app routing in this folder. The build process outputs HTML, CSS and JS files that you can host on any web server and open directly in a browser.

Other Platform Folders

We don’t see ios, macos or linux folders here because we didn’t tick those platform options when creating the project. The underlying logic for each of these platforms works exactly the same way though.

ios: Native Xcode project for Apple iOS, used to build IPA files and release apps for iPhone devices.

macos: Native Cocoa project for macOS, used to build desktop clients for Mac computers.

linux: GTK-based native desktop project for Linux operating systems.

You can switch target platforms from the dropdown menu in the top-right corner of Android Studio to build app versions for different systems. You can also run builds straight from the command line. Behind the scenes, clicking the green play button to run your selected platform simply executes equivalent Flutter CLI commands.

# Launch Android build, uses configurations inside the android folder
flutter run -d android

# Launch Windows desktop build, loads the C++ project from windows folder
flutter run -d windows

# Launch web build, loads the HTML entry from web folder
flutter run -d chromeCode language: PHP (php)

Navigate to runner/main.cpp inside the windows folder.

#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>

#include "flutter_window.h"
#include "utils.h"

int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
                      _In_ wchar_t *command_line, _In_ int show_command) {
  // Attach to console when present (e.g., 'flutter run') or create a
  // new console when running with a debugger.
  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
    CreateAndAttachConsole();
  }

  // Initialize COM, so that it is available for use in the library and/or
  // plugins.
  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);

  flutter::DartProject project(L"data");

  std::vector<std::string> command_line_arguments =
      GetCommandLineArguments();

  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));

  FlutterWindow window(project);
  Win32Window::Point origin(10, 10);
  Win32Window::Size size(1280, 720);
  if (!window.Create(L"myproject", origin, size)) {
    return EXIT_FAILURE;
  }
  window.SetQuitOnClose(true);

  ::MSG msg;
  while (::GetMessage(&msg, nullptr, 0, 0)) {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
  }

  ::CoUninitialize();
  return EXIT_SUCCESS;
}
Code language: PHP (php)

When compiling for Windows Desktop, this main.cpp file acts as the true program entry point. The system runs main.cpp first, then loads your lib/main.dart Flutter code afterward.

Likewise, if you open the android folder, you’ll notice its internal structure matches standard Android projects built with Kotlin or Java.

You’ll find familiar components including the src directory, AndroidManifest.xml, and MainActivity class — everything you recognize from native Android development. That’s no coincidence: building Android apps with Flutter still boots up from this native android folder under the hood.

Open the web folder, and you’ll also see index.html, the main entry file for web deployments.

Understanding Dart Files

The main.dart file inside lib will be where you spend most of your development time. You can create subfolders and add additional Dart files within the lib directory to organize your codebase.

Let’s open main.dart and break it down.

// Import Material Design UI component library
import 'package:flutter/material.dart';

// Main program entry point
void main() {
  runApp(const MyApp());
}

// Root stateless application widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      // Global theme configuration
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      // Default home screen
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

// Stateful widget for the main home screen
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  // Page title parameter passed in
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

// State class managing logic and data for the home screen
class _MyHomePageState extends State<MyHomePage> {
  // Counter numeric variable
  int _counter = 0;

  // Method to increment the counter value
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // Base layout scaffold for the page
    return Scaffold(
      // Top app navigation bar
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      // Main page content area
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter', // Render the counter number variable as text
              style: Theme.of(context).textTheme.headlineMedium, // Text styling rule
            ),
          ],
        ),
      ),
      // Floating action button in bottom-right corner
      // onPressed triggers increment logic, tooltip shows hover text, child defines icon
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}Code language: JavaScript (javascript)

1. Program Entry Section

import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
Code language: JavaScript (javascript)
  • Imports Google’s official Material Design library, a full set of pre-built UI widgets including buttons, page layouts and text components. Apple provides its own separate UI framework for iOS.
  • main acts as the single entry point for all Dart applications. The runApp() function initializes the app and mounts the root MyApp widget to the screen.

2. MyApp: Global Root Widget

This is a StatelessWidget, meaning it holds no mutable state. We’ll cover stateful vs stateless widgets in more detail later; for now just keep this basic concept in mind.

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget serves as the root of your entire application
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
Code language: JavaScript (javascript)
  • Global app settings: Sets your app display name, universal theme styling, and default landing page.
  • MaterialApp: The top-level wrapper for Material Design apps that handles routing, global themes and page titles centrally.
  • The home parameter defines MyHomePage as the screen users see when launching the app.

3. MyHomePage: Main Home Screen Widget

This is the default screen loaded when you open the app or window, and it’s a StatefulWidget. We’ll break down stateful widgets fully in later sections.

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}Code language: JavaScript (javascript)
  • We use a stateful widget here because the screen stores dynamic changing data — our counter number.
  • The title string value gets passed into the widget externally and accessed within the state class via widget.title.
  • Every StatefulWidget requires a paired state class, in this case _MyHomePageState, which stores all page variables and user interaction logic.

4. _MyHomePageState: State Logic Class

This companion state class manages all page logic, rendering output and UI updates.

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(

        backgroundColor: Theme.of(context).colorScheme.inversePrimary,

        title: Text(widget.title),
      ),
      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}Code language: JavaScript (javascript)
  1. int _counter = 0: Dynamic page variable storing our counter value.
  2. _incrementCounter(): The function triggered when tapping the button
    • setState() tells Flutter our stored data has changed, triggering a full UI refresh.
    • Increases the counter value by one.
  3. The build() method runs every time the UI refreshes, returning the full page layout structure.

5. Scaffold: Page Layout Template

Scaffold is the base layout template used inside our _MyHomePageState class.

  • appBar: The top header/title bar of the screen.
  • body: The main content area of the page
    • Center aligns all child widgets to the screen center; Column arranges text elements vertically.
  • floatingActionButton: The circular plus icon button fixed in the bottom-right corner, linked to our counter increment function.

Full App Runtime Workflow

  1. App launches → main function executes → loads the root MyApp widget.
  2. MyApp renders the MaterialApp wrapper → loads the default home screen MyHomePage.
  3. The page renders its top title bar, centered text content and floating add button.
  4. Tap the button → _incrementCounter runs, calls setState to redraw the UI → counter number updates on screen.

Leave a Reply

Your email address will not be published. Required fields are marked *