Provider package in Flutter serves us in many ways. Flutter team recommends it as the best state management architecture. But that is not the end of the story. We can use Provider for many purposes, that also includes passing a global style across the flutter app. However, understanding Provider will remain incomplete if we don’t understand the concept of generics value or the type of Provider.
This section on Provider is intended for beginners, so we assume we need to start from the beginning.
Firstly, we can provide any type of value through Provider.
Take a look at the code below.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/global_theme.dart';
import 'view/home.dart';
void main() {
runApp(
/// Providers are above [Root App] instead of inside it, so that tests
/// can use [Root App] while mocking the providers
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => GlobalTheme()),
Provider<int>(create: (context) => 1),
Provider<String>(create: (context) => 'Hello Flutter'),
],
child: const Home(),
),
);
}
Forget about the first line. Take a look at the middle line and let’s try to understand it first.
Provider<int>(create: (context) => 1),
In this case, Provider passes an integer value inside <> brackets. That generic value tells Flutter what type of provider to look for. And we’ve returned a value 1.
The second line tells us another stroy.
Provider<String>(create: (context) => 'Hello Flutter'),
This time Flutter will look for a String or text; so we’ve returned a text: “Hello Flutter”.
Once we’ve passed this generic value we can try to access that value anywhere, in the widget tree. However, that value must be provided there inside the build method.
Why so?
Because context works like a road. Each different Provider takes different road, or context. Inside the build method, all roads, contexts merge and separate the value. As a result we can access different value quite easily.
Flutter works seamlessly with Provider and goes up through the widget tree to find the exact value.
If it doesn’t find that generic value, exception is thrown.
Let’s try to understand more about the generic value or type that Provider understands.
Not that it should be only integer or String. It could be any type, even an Object. That means, we can pass a whole class properties and methods through Provider.
The first line of code tells that story. However, in a different way, although.
ChangeNotifierProvider(create: (_) => GlobalTheme()),
Here, in the above line we’ve used ChangeNotifierProvider, instead of Provider. There are reasons to do that. We’ve discussed that already.
However, the most important reason is, if we want to change the state, or call a class method through Provider, the ChangeNotifierProvider is the best choice.
Now, we can try to grab those values. First of all, consider the above line.
We have passed a custom class GlobalTheme. That defines the global theme of the app. Certainly, we can define different ThemeData object to make every page of our app look different.
But at present, it’s enough to get the idea.
import 'package:flutter/material.dart';
class GlobalTheme with ChangeNotifier {
final globalTheme = ThemeData(
primarySwatch: Colors.deepOrange,
textTheme: const TextTheme(
bodyText1: TextStyle(
fontSize: 22,
),
bodyText2: TextStyle(
color: Colors.blue,
fontSize: 18,
fontWeight: FontWeight.bold,
),
caption: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
),
headline1: TextStyle(
color: Colors.deepPurple,
fontSize: 50,
fontFamily: 'Allison',
),
headline2: TextStyle(
color: Colors.deepOrange,
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
appBarTheme: const AppBarTheme(
backgroundColor: Colors.amber,
// This will control the "back" icon
iconTheme: IconThemeData(color: Colors.red),
// This will control action icon buttons that locates on the right
actionsIconTheme: IconThemeData(color: Colors.blue),
centerTitle: false,
elevation: 15,
titleTextStyle: TextStyle(
color: Colors.deepPurple,
fontWeight: FontWeight.bold,
fontFamily: 'Allison',
fontSize: 40,
),
),
);
}
Next, we can have these values in our home page. To understand the whole widget tree, you can read the full code snippets in this GitHub repository.
import 'package:build_blog_with_flutter/model/global_theme.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Testing Global Theme with Provider',
style: Theme.of(context).appBarTheme.titleTextStyle,
),
),
body: const HomeBody(),
);
}
}
/// pushing to main now
class HomeBody extends StatelessWidget {
const HomeBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final int globalInt = Provider.of<int>(context);
final String globalString = Provider.of<String>(context);
final ThemeData globalTheme = Provider.of<GlobalTheme>(context).globalTheme;
return Center(
child: Column(
children: [
Container(
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.all(5),
child: Text(
'$globalInt',
//style: Theme.of(context).textTheme.bodyText1,
style: globalTheme.textTheme.bodyText1,
),
),
Container(
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.all(5),
child: Text(
globalString,
//style: Theme.of(context).textTheme.bodyText2,
style: globalTheme.textTheme.bodyText2,
),
),
Container(
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.all(5),
child: Text(
'Headline 1 theme style again provided by provider',
//style: Theme.of(context).textTheme.headline2,
style: globalTheme.textTheme.headline1,
),
),
],
),
);
}
}
As a result, we see the following screenshot where we get the provided integer, String value; and, along with that we can also apply our custom theme to our app.
![Flutter provider example](https://i0.wp.com/sanjibsinha.com/wp-content/uploads/2021/11/Flutter-provider-example.jpg?ssl=1)
In the above code, we can avoid using the custom theme. Actually we had provided the global custom theme through the following lines:
ChangeNotifierProvider(create: (_) => GlobalTheme()),
...
final ThemeData globalTheme = Provider.of<GlobalTheme>(context).globalTheme;
If we don’t do that, no longer the provided custom theme works. And in that case, the rest provided value appears on the screen with the default ThemeData that take another context or road.
As a result, the look of the app gets changed.
![Flutter app without provider backed theme](https://i0.wp.com/sanjibsinha.com/wp-content/uploads/2021/11/Flutter-app-without-provider-backed-theme.jpg?ssl=1)
Anyway, the headline was wrong. It should have been read like, “Headline 1 theme style provided by default theme.” 🙂
We hope, it now makes sense, how Provider works and we get provided value anywhere in the widget tree.
Leave a Reply