Skip to content
Flutter Explained — Cross-Platform Mobile Development with Dart

Flutter Explained — Cross-Platform Mobile Development with Dart

DodaTech Updated Jun 6, 2026 9 min read

Flutter is Google’s UI toolkit for building natively compiled applications for mobile, web, and desktop from a single codebase using the Dart programming language and a unique widget-based architecture.

What You’ll Learn

You’ll understand Flutter’s widget tree, manage state with setState, use hot reload for rapid development, and build a cross-platform app using Dart code examples with expected output.

Why Flutter Matters

Flutter is one of the fastest-growing cross-platform frameworks. It’s used by Google (Google Pay), Alibaba, and BMW. At DodaTech, we’re exploring Flutter for our mobile security scanner interface because it renders at 60fps on both platforms and produces visually consistent UIs. Unlike React Native which bridges to native components, Flutter draws everything itself — giving pixel-perfect control.

Flutter Learning Path

    flowchart LR
  A[Dart Basics] --> B[Flutter]
  B --> C[Widgets & Layouts]
  C --> D[State Management]
  D --> E[Navigation]
  E --> F[Networking & APIs]
  F --> G[Platform Channels]
  G --> H[App Store & Play Store]
  B:::current

  classDef current fill:#f90,color:#fff,stroke:#333,stroke-width:2px
  
Prerequisites: Basic Dart programming knowledge (variables, functions, classes). Familiarity with Python or JavaScript is helpful. Install Flutter SDK from flutter.dev.

How Flutter Is Different

Most cross-platform frameworks (like React Native) use a “bridge” to communicate with native UI components. Flutter does something completely different: it draws every pixel on the screen using its own rendering engine called Skia.

Think of it this way:

  • React Native is like ordering from two different restaurants (Android and iOS kitchens) using a translator. The translator might get things wrong or be slow.
  • Flutter is like having your own kitchen with its own ingredients. You cook the same meal everywhere, and it tastes identical on both platforms.

This approach means Flutter apps look and feel the same on Android and iOS, which is great for brand consistency. The trade-off is larger app sizes (Flutter includes its own engine in the binary).

Everything Is a Widget

In Flutter, everything is a widget. The text you see is a widget. The padding around it is a widget. The row containing those elements is a widget. Even your entire app is a widget.

Widgets form a tree structure:

    graph TD
  A[MyApp - MaterialApp] --> B[Scaffold]
  B --> C[AppBar]
  B --> D[Center]
  D --> E[Column]
  E --> F[Text 'Hello']
  E --> G[SizedBox - spacing]
  E --> H[ElevatedButton]
  

Let’s build a simple Flutter app step by step.

Step 1: Create a New Project

flutter create hello_dodatech
cd hello_dodatech
flutter run

This creates a counter app template. Let’s replace it with our own app.

Step 2: Understanding the Main Entry Point

// lib/main.dart
import 'package:flutter/material.dart';

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

Every Flutter app starts with main(), which calls runApp(). runApp takes the root widget of your application and mounts it to the screen.

Step 3: Build the App Widget

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello DodaTech',
      theme: ThemeData(
        colorSchemeSeed: Colors.teal,
        useMaterial3: true,
      ),
      home: const HomeScreen(),
    );
  }
}

Stateless vs Stateful: A StatelessWidget is immutable — once built, it never changes. A StatefulWidget can update dynamically.

MaterialApp sets up Material Design theming. It’s like the stage for your app — it provides navigation, theming, and localization.

Step 4: Create the Home Screen

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // State variables
  final TextEditingController _nameController = TextEditingController();
  String _greeting = 'Welcome to Flutter!';
  final List<String> _items = [
    'Learn Flutter Widgets',
    'Build an App',
    'Master State Management',
    'Publish to Stores',
  ];

  @override
  void dispose() {
    _nameController.dispose();
    super.dispose();
  }

  void _onGreet() {
    setState(() {
      final name = _nameController.text.trim();
      if (name.isEmpty) {
        _greeting = 'Please enter a name!';
      } else {
        _greeting = 'Hello, $name!';
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Hello DodaTech'),
        backgroundColor: Colors.teal,
        foregroundColor: Colors.white,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Greeting text
            Text(
              _greeting,
              style: Theme.of(context).textTheme.headlineSmall,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 16),

            // Text input field
            TextField(
              controller: _nameController,
              decoration: const InputDecoration(
                labelText: 'Enter your name',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.person),
              ),
            ),
            const SizedBox(height: 16),

            // Greet button
            ElevatedButton(
              onPressed: _onGreet,
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.teal,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(vertical: 16),
              ),
              child: const Text('Greet Me'),
            ),
            const SizedBox(height: 24),

            // List header
            Text(
              'Learning Roadmap:',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 8),

            // List of items
            Expanded(
              child: ListView.builder(
                itemCount: _items.length,
                itemBuilder: (context, index) {
                  return Card(
                    child: ListTile(
                      leading: CircleAvatar(
                        backgroundColor: Colors.teal.shade100,
                        child: Text('${index + 1}'),
                      ),
                      title: Text(_items[index]),
                      trailing: const Icon(Icons.arrow_forward_ios),
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Breaking down the code:

  • StatefulWidget and State — Together they create a widget that can update. The widget itself is immutable (configuration), but the State object persists and can change
  • TextEditingController — Manages the text input. Think of it as a bridge between the TextField widget and your code. We call dispose() on it when the screen is destroyed to prevent memory leaks
  • setState() — This is Flutter’s way of saying “rebuild this widget with new data.” Calling setState triggers the build() method again, updating the UI
  • Scaffold — Provides the basic Material Design layout structure (app bar, body, bottom navigation)
  • ListView.builder — Efficiently builds a scrollable list. It only creates widgets for visible items, like recycling cells in Android/iOS
  • SizedBox — A simple widget that adds fixed space between other widgets

Expected Output

When you run flutter run:

  1. An app with a teal AppBar showing “Hello DodaTech”
  2. “Welcome to Flutter!” centered below
  3. A text field with a person icon and “Enter your name” label
  4. A “Greet Me” button
  5. Below that, a numbered card list with the four learning items
  6. Each card has a forward arrow icon on the right
  7. When you type a name and tap “Greet Me”, the greeting text updates to “Hello, [Name]!”

Navigation: Adding a Second Screen

Flutter uses a Navigator widget to manage screens (called “routes”). Let’s add a detail screen:

// Add to main.dart or create a new file

class ProfileScreen extends StatelessWidget {
  final String userName;

  const ProfileScreen({super.key, required this.userName});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Your Profile'),
        backgroundColor: Colors.teal,
        foregroundColor: Colors.white,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(
              Icons.account_circle,
              size: 100,
              color: Colors.teal,
            ),
            const SizedBox(height: 24),
            Text(
              'Hello, $userName!',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context); // Go back to home
              },
              child: const Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

To navigate from HomeScreen, replace the ElevatedButton’s onPressed:

onPressed: () {
  final name = _nameController.text.trim();
  if (name.isEmpty) {
    setState(() => _greeting = 'Please enter a name!');
  } else {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => ProfileScreen(userName: name),
      ),
    );
  }
},

How navigation works:

  • Navigator.push() adds a new route to the navigation stack (like placing a new card on top of a deck)
  • MaterialPageRoute defines the transition animation and the screen to show
  • Navigator.pop() removes the current route and returns to the previous screen

Hot Reload — Your Superpower

Flutter’s hot reload is one of its best features. When you edit your code and save (or press r in the terminal), Flutter rebuilds the widget tree in milliseconds — without losing the app’s state.

Imagine editing a document and seeing your changes appear instantly without closing and reopening the file. That’s hot reload.

Try it now: change the “Welcome to Flutter!” greeting to “Flutter is Amazing!” and save. The screen updates instantly.

Security Angle: Input Validation

In our Flutter code, we use _nameController.text.trim() to clean user input. For production Flutter apps:

  • Use TextFormField with a validator property for form validation
  • Never store sensitive data in plain SharedPreferences — use flutter_secure_storage
  • Sanitize text before displaying it to prevent injection in WebViews
  • Use http package with certificate pinning for secure API calls
  • Check that URLs start with https:// before making network requests

DodaTech’s security scanner tools use similar text validation patterns when analyzing file names for suspicious patterns.

Common Mistakes Beginners Make

  1. Calling setState after dispose: If you have async operations, check mounted before calling setState.
  2. Not disposing controllers: TextEditingController, AnimationController, and ScrollController must be disposed to prevent memory leaks.
  3. Using Column without Expanded for scrollable content: If content exceeds the screen, wrap it in Expanded + SingleChildScrollView.
  4. Forgetting the const keyword: Flutter widgets are immutable. Use const constructors where possible for performance.
  5. Deep widget nesting: Deeply nested widgets hurt readability. Extract widgets into separate methods or classes.
  6. Not handling null safety: Dart is null-safe. Use ? for nullable types and ! only when you’re absolutely sure.
  7. Blocking the UI thread: Heavy computations should use compute() (Flutter’s isolate function) to run on a separate thread.

Practice Questions

  1. What is the difference between StatelessWidget and StatefulWidget?
  2. What does setState() do?
  3. How do you navigate to a new screen in Flutter?
  4. What is the widget at the root of every Material Design Flutter app?
  5. Why must you dispose TextEditingController?

Answers:

  1. StatelessWidget never changes after building; StatefulWidget can update dynamically using setState.
  2. It marks the widget as needing rebuild, triggering the build() method with updated state.
  3. Use Navigator.push(context, MaterialPageRoute(builder: ...)).
  4. MaterialApp — it provides theming, navigation, and Material Design structure.
  5. To free resources and prevent memory leaks. Controllers hold references that need cleanup.

Challenge

Add a “Favorites” feature. Each card in the list should have a heart icon on the right. When tapped, it toggles between filled (favorited) and outlined (not favorited) state. Use a Set<int> to track which indices are favorited.

Real-World Task

Build a “Quote of the Day” app. Display a random quote from a predefined list. Include a button to generate a new random quote. Add a second screen that shows all quotes in a scrollable list. Style it with a clean, modern design using Flutter’s ThemeData.

Featured Snippet

What is Flutter?

Flutter is Google’s open-source UI toolkit that builds natively compiled applications for mobile, web, and desktop from a single Dart codebase, using a widget-based architecture and its own Skia rendering engine for consistent cross-platform performance.

FAQ

Do I need a Mac to develop Flutter apps?
No. Flutter supports development on Windows, macOS, and Linux. For iOS builds, you still need a Mac. For Android, any platform works.
What programming language does Flutter use?
Dart, also created by Google. Dart is optimized for UI development with features like null safety, async/await, and ahead-of-time (AOT) compilation for fast startup.
Is Flutter good for production apps?
Yes. Google Pay, Alibaba, eBay, and BMW use Flutter in production. It’s stable and has been production-ready since Flutter 1.0 in 2018.
What’s the difference between Flutter and React Native?
Flutter draws its own UI using Skia (consistent look on both platforms). React Native bridges to native UI components (platform-specific look). Flutter uses Dart; React Native uses JavaScript.

Try It Yourself

▶ Try It Yourself Edit the code and click Run

What’s Next

What’s Next

Congratulations on completing this Flutter tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro