0
0
Fluttermobile~20 mins

MVVM pattern in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Counter MVVM Screen
A simple counter app using MVVM pattern in Flutter. The screen shows a number and two buttons to increase or decrease the count. The ViewModel manages the count state and notifies the UI to update.
Target UI
---------------------
|   Counter MVVM    |
|-------------------|
|                   |
|       0           |
|                   |
|  [-]       [+]    |
---------------------
Use MVVM pattern: separate View, ViewModel, and Model logic
ViewModel holds the counter value and exposes increment and decrement methods
View listens to ViewModel changes and updates UI accordingly
Two buttons: '+' to increment, '-' to decrement the counter
Display the current count in the center
Use ChangeNotifier and ChangeNotifierProvider from provider package for state management
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// TODO: Create CounterViewModel class here

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

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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => CounterViewModel(),
      child: const MaterialApp(
        home: CounterScreen(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    // TODO: Build UI that listens to CounterViewModel
    return Scaffold(
      appBar: AppBar(title: const Text('Counter MVVM')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // TODO: Display counter value
            // TODO: Add buttons to increment and decrement
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterViewModel extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }

  void decrement() {
    _count--;
    notifyListeners();
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => CounterViewModel(),
      child: const MaterialApp(
        home: CounterScreen(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter MVVM')),
      body: Center(
        child: Consumer<CounterViewModel>(
          builder: (context, viewModel, child) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  '${viewModel.count}',
                  style: const TextStyle(fontSize: 48),
                ),
                const SizedBox(height: 20),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    ElevatedButton(
                      onPressed: viewModel.decrement,
                      child: const Text('-'),
                    ),
                    const SizedBox(width: 20),
                    ElevatedButton(
                      onPressed: viewModel.increment,
                      child: const Text('+'),
                    ),
                  ],
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

This app uses the MVVM pattern by separating the UI (View) from the business logic (ViewModel). The CounterViewModel class holds the counter state and methods to change it. It extends ChangeNotifier so it can notify the UI when the data changes.

The MyApp widget provides the ViewModel to the widget tree using ChangeNotifierProvider from the provider package.

The CounterScreen widget listens to the ViewModel using Consumer. It rebuilds the UI when the count changes, showing the current count and two buttons to increment or decrement the value.

This clear separation makes the app easier to maintain and test.

Final Result
Completed Screen
---------------------
|   Counter MVVM    |
|-------------------|
|                   |
|       0           |
|                   |
|  [-]       [+]    |
---------------------
Tapping '+' increases the number displayed by 1
Tapping '-' decreases the number displayed by 1
The number updates immediately on screen
Stretch Goal
Add a reset button that sets the counter back to zero
💡 Hint
Add a reset() method in CounterViewModel that sets _count to 0 and calls notifyListeners(). Add a new button in the UI that calls reset() when pressed.