introduce

Dynamically switch topics using Provider status management

To learn the content of this chapter, you must master the state management of Provider. If you don’t understand, please open my home page, search for Provider, and then return to this blog

Theme Style Overview

factory ThemeData({
  Brightness brightness, // Apply the overall theme brightness. Used for widgets such as buttons to determine what color to choose when you are not using a primary or accent color.
  MaterialColor primarySwatch,// Define a single color and a block of ten shades.
  Color primaryColor, // Background color for the main part of the application (toolbars, TAB bars, etc.)
  Brightness primaryColorBrightness, // primaryColor brightness. ICONS used to determine the color of text and placed above the main color (for example, toolbar text).
  Color primaryColorLight, // A lighter version of primaryColor
  Color primaryColorDark, // The darker version of primaryColor
  Color accentColor, // The foreground color of the widget (knob, text, overlay edge effect, etc.).
  Brightness accentColorBrightness, // accentColor brightness.
  Color canvasColor, // The default color of materialType.canvas
  Color scaffoldBackgroundColor, // The default colour of Scaffold. The background color of a typical Material application or page within an application.
  Color bottomAppBarColor, // The default color of BottomAppBar
  Color cardColor, // The color of Card
  Color dividerColor, // The colors of the Divider and PopupMenuDivider are also used between listtiles, between rows of the DataTable, etc.
  Color highlightColor, // Select the highlight color to use during splash animation, or to indicate items in the menu.
  Color splashColor,  // The color of the ink splash. InkWell
  InteractiveInkFeatureFactory splashFactory, // Define the appearance of the splash produced by the InkWell and InkResponse reactions.
  Color selectedRowColor, // Use to highlight the color of the selected row.
  Color unselectedWidgetColor, // The color used for widgets that are inactive (but enabled). For example, an unchecked check box. This is usually contrasted with accentColor. Also see disabledColor.
  Color disabledColor, // Disable the color of the part in the state, regardless of its current state. For example, a disabled check box (which can be checked or unchecked).
  Color buttonColor, // The default padding color for Material used in the RaisedButton.
  ButtonThemeData buttonTheme, // Define the default configuration of button widgets, such as RaisedButton and FlatButton.
  Color secondaryHeaderColor, // The color of the PaginatedDataTable title when the row is selected.
  Color textSelectionColor, // The color of the text selected by the text box, such as TextField
  Color cursorColor, // The color of the cursor in a text box, such as TextField
  Color textSelectionHandleColor,  // Adjusts the color of the handle to the currently selected text part.
  Color backgroundColor, // A color that contrasts with the main color, e.g. used as the rest of a progress bar.
  Color dialogBackgroundColor, // The background color of the Dialog element
  Color indicatorColor, // The color of the selected TAB indicator in the TAB.
  Color hintColor, // The color used to prompt text or placeholder text, as in TextField.
  Color errorColor, // The color used for input validation errors, such as in TextField
  Color toggleableActiveColor, // The color used to highlight the active state of swappable widgets like Switch, Radio, and Checkbox.
  String fontFamily, // Text font
  TextTheme textTheme, // The color of the text contrasts with the color of the card and canvas.
  TextTheme primaryTextTheme, // Contrast the text theme with primaryColor
  TextTheme accentTextTheme, // Contrast the text theme with accentColor.
  InputDecorationTheme inputDecorationTheme, // Default InputDecorator, TextField, and TextFormField values based on this topic.
  IconThemeData iconTheme, // An icon theme that contrasts the card and canvas colors
  IconThemeData primaryIconTheme, // Contrast the icon theme with primaryColor
  IconThemeData accentIconTheme, // An icon theme that contrasts with accentColor.
  SliderThemeData sliderTheme,  // Used to render the color and shape of the Slider
  TabBarTheme tabBarTheme, // Theme for customizing the size, shape, and color of TAB bar indicators.
  CardTheme cardTheme, // Card color and style
  ChipThemeData chipTheme, // Chip's color and style
  TargetPlatform platform, 
  MaterialTapTargetSize materialTapTargetSize, // Configures the hit test size for some Material components
  PageTransitionsTheme pageTransitionsTheme, 
  AppBarTheme appBarTheme, // Theme for customizing Appbar colors, heights, brightness, iconTheme, and textTheme.
  BottomAppBarTheme bottomAppBarTheme, // Customize the shape, height, and color of the BottomAppBar theme.
  ColorScheme colorScheme, // There are 13 colors, which can be used to configure the colors of most components.
  DialogTheme dialogTheme, // Customize the theme shape of the Dialog
  Typography typography, // used to configure the color and geometry TextTheme values for TextTheme, primaryTextTheme, and accentTextTheme.
  CupertinoThemeData cupertinoOverrideTheme 
})
Copy the code

In actual combat

Introduction of package

Open pubspec.yaml of the Flutter project and directory because of the use of Provider state management and shared_preferences data persistence

Shared_preferences: ^ 0.5.12 + 4 provider: ^ 4.3.2 + 3Copy the code

Add a global theme color

To set the theme, we need to know how many themes (colors) our app needs. For this theme, we need to define a global list

Dart file to save the global theme color

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

final List<Color> themeList = [
  Colors.blue,
  Colors.black,
  Colors.red,
  Colors.purple,
  Colors.indigo,
  Colors.yellow,
  Colors.green,
];

Copy the code

We’ll just define these colors, and if you want more, you can define them yourself

Add global topic state

Since our theme is dynamic, we need to notify the interface to refresh after changing. Here we need to use state management, if you are not familiar with Provider state management, please learn first and then watch

Create a provider folder in the project and directory lib. Create a theme_provider.dart file in the folder to save the current theme status value

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:zhong_mei_utils_flutter/global/Global.dart';

// Inherit ChangeNotifier
class ThemeProvider with ChangeNotifier {
  Color _color = themeList.first;// The default is the first in the list of theme colors we set

  void setTheme(int index) {// Provide external methods to modify the theme
    print(index.toString());
    _color = themeList[index];
    notifyListeners();
  }

  Color get color => _color;// Get the current topic
}

Copy the code

The topic state class is created, added to the project, and let the project manage the state to modify main.dart

return runApp(MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) => UserProvider()),
            ChangeNotifierProvider(create: (context) => ThemeProvider()),
          ],
          child: MyApp(),
        ));
Copy the code

With the topic state set, use the global topic state

Generally speaking, one app has only one MaterialApp, and our topic is set in the MaterialApp, so find our MaterialApp and add the following code

return MaterialApp(
      theme: ThemeData.light().copyWith(
        primaryColor: Provider.of<ThemeProvider>(context).color,
        buttonTheme: ButtonThemeData(
          buttonColor: Provider.of<ThemeProvider>(context).color,
          textTheme: ButtonTextTheme.normal,
        ),
      ),
Copy the code

The previous code sets the app theme color and button color to use the color in the state manager, while the button text color is highlighted. If the button background color is black, the button text color is automatically white

Theme Modification interface

Add settings_theme.dart.dart under lib

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:weui/icon/index.dart';
import 'package:zhong_mei_utils_flutter/global/Global.dart';
import 'package:zhong_mei_utils_flutter/provider/ThemeProvider.dart';

class SettingsView extends StatefulWidget {
  @override
  _SettingsViewState createState() => _SettingsViewState();
}

class _SettingsViewState extends State<SettingsView> {
  int _index;// Where in the global theme list is our current theme set?
  @override
  void initState() {
    super.initState();
    loadData();// Query current persistent data
  }

  void loadData() async {
    SharedPreferences sp = await SharedPreferences.getInstance();// Get the persistent action object
    setState(() {
      _index = sp.getInt("theme")??0;// Query the theme field saved in the persistence framework. If it is null, it defaults to 0
    });
  }

  Widget _itemBuilder(BuildContext context, int index) {
    return GestureDetector(
      child: Container(
        width: double.infinity,
        height: 50,
        margin: EdgeInsets.only(top: 10, bottom: 10),
        decoration: BoxDecoration(
          color: themeList[index],
          borderRadius: BorderRadius.all(Radius.circular(20)), ), child: _index ! = index ? Text("")// If not selected, there is nothing
            : Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Icon(
                    WeIcons.hook,// If it is selected, an icon is given. This icon is a check box, you can find it by yourself
                    color: Colors.white,
                  ),
                  SizedBox(width: 16),
                ],
              ),
      ),
      onTap: () async {
        SharedPreferences sp = await SharedPreferences.getInstance();
        sp.setInt("theme", index);// Click to modify the theme database in the persistence framework
        Provider.of<ThemeProvider>(context, listen: false).setTheme(index);// Change the global status to the selected value
        setState(() {
          _index = index;// Set the current interface selection value, refresh the check box}); }); }@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Set theme"),
        centerTitle: true,
        elevation: 10,
      ),
      body: Padding(
        padding: EdgeInsets.all(20), child: Scrollbar( child: ListView.builder( itemBuilder: _itemBuilder, itemCount: themeList.length, ), ), ), ); }}Copy the code

At this point, we have finished, but there is a problem, that is, we have no problem with normal use, but after exiting the app, we did not read the persistent theme, so we changed the default first color

At this time we want to read data to see the theme, to understand a concept app starts, have white, developers can start to do a figure commonly, to cover up bad, we need to know here, hang because app on load some things, not rendering interface, so we load the theme should also be in the app before loading

Otherwise, the interface is rendered, but the theme is not read, causing the theme to display the default color first, and then display the theme color we set

So there is code in the Main. dart of the Flutter project

return runApp(MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) => UserProvider()),
            ChangeNotifierProvider(create: (context) => ThemeProvider()),
          ],
          child: MyApp(),
        ));
Copy the code

As you can see, there is no UI rendering before Child: MyApp(), so we need to read the theme before return runApp and generate the ThemeProvider object

int theme;// Add a variable to receive a database read return

void main() async {// Async is added since reading from the database requires async
  await loadData();// Read the topic saved by the database
      ThemeProvider themeProvider = ThemeProvider();// New a topic state object
      themeProvider.setTheme(theme ?? 0);// Set the object to the subject we read
      return runFxApp(
        MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) => UserProvider()),
            ChangeNotifierProvider(create: (context) => themeProvider),ThemeProvider() is the ThemeProvider object
          ],
          child: MyApp(),
        ),
        // onEnsureInitialized: (info) {},
        enableLog: false,
        uiBlueprints: uiSize,
      );
}

void loadData() async {
  SharedPreferences sp = await SharedPreferences.getInstance();
  theme = sp.getInt("theme")??0;// Return 0 if read is null
}
Copy the code

After the above changes, we finished reading the persistent theme and preloaded the theme at app startup

Implementation effect demonstration

As you can see, the theme is up to date by the time you start the project and get to the landing page. Here we use persistence