Skip to content
Dustin Catap edited this page Jun 19, 2024 · 2 revisions

A view is a collection of visible elements that receives user inputs.

ViewModelBuilder

This is a StatefulWidget that creates a view model and provides it to its child widgets. It requires a create function to create the view model and a builder function to build the UI based on the view model.

Given the following view model:

class HomeViewModel extends ViewModel {
  final ValueNotifier<int> _count = ValueNotifier(0);

  ValueListenable<int> get count => _count;

  void increment() => _count.value++;
}

We can use ViewModelBuilder to create the view model and build the UI:

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<HomeViewModel>(
      create: (BuildContext context) => HomeViewModel(),
      builder: (BuildContext context, HomeViewModel viewModel) {
        return Scaffold(
          appBar: AppBar(title: const Text('Home')),
          body: Text('Count value: ${viewModel.count}'),
          floatingActionButton: FloatingActionButton(
            onPressed: viewModel.increment,
            child: const Icon(Icons.add),
          ),
        );
      },
    );
  }
}
  • create is a function that creates the view model, and it is called only once. You can use other ways of creating the view model, such as using a service locator.
  • builder is a function that builds the UI based on the view model. It is called initially, and is called again when the framework notifies the widget to rebuild.
  • onDispose is a function that is called when the widget is removed from the tree. You can use it to clean up resources.

AutoViewModelBuilder

This is a StatelessWidget that automatically builds a view model and provides it to its child widgets. It uses a ViewModelBuilder to create the view model and a ServiceLocator to get an instance of the view model.

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AutoViewModelBuilder<HomeViewModel>(
      builder: (BuildContext context, HomeViewModel viewModel) {
        return Scaffold(
          appBar: AppBar(title: const Text('Home')),
          body: Text('Count value: ${viewModel.count}'),
          floatingActionButton: FloatingActionButton(
            onPressed: viewModel.increment,
            child: const Icon(Icons.add),
          ),
        );
      },
    );
  }
}
  • onCreate is a function that is called when the view model is created. You can use it for additional initialization.
  • builder is a function that builds the UI based on the view model. It is called initially, and is called again when the framework notifies the widget to rebuild.
  • onDispose is a function that is called when the widget is removed from the tree. You can use it to clean up resources.

Accessing the view model

You can access the view model using ViewModelProvider.of<T>(context) or context.viewModel<T>(). This looks up the nearest ancestor ViewModelProvider widget and returns the view model.

class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder<HomeViewModel>(
      create: (BuildContext context) => HomeViewModel(),
      child: const Scaffold(
        appBar: AppBar(title: Text('Home')),
        body: _Counter(),
        floatingActionButton: _CounterButton(),
      ),
    );
  }
}

class _Counter extends StatelessWidget {
  const _Counter();

  @override
  Widget build(BuildContext context) {
    return Text('Count value: ${context.viewModel<HomeViewModel>().count}');
    // or
    return Text('Count value: ${ViewModelProvider.of<HomeViewModel>(context).count}');
  }
}

class _CounterButton extends StatelessWidget {
  const _CounterButton();

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: context.viewModel<HomeViewModel>().increment,
      // or
      onPressed: ViewModelProvider.of<HomeViewModel>(context).increment,
      child: const Icon(Icons.add),
    );
  }
}

💡 TIP

  • This can be used if you want to breakdown your UI into smaller widgets and still have access to the view model.
  • You can replace the builder parameter with a child parameter since we are not using the view model in the builder function.
Clone this wiki locally