flutterthemes

Flutter set theme from a list


I am trying to add a list of theme that user can chose one here is my list

import 'package:flutter/material.dart';

class ThemeModel {
  final Color surface;
  final Color primary;
  final Color secondary;
  final Color onSurface;

  ThemeModel({
    required this.surface,
    required this.primary,
    required this.secondary,
    required this.onSurface,
  });
}

final List<ThemeModel> themes = [
  ThemeModel(
    surface: Color(0xFFF0EAD6),
    primary: Color(0xFF6C9A8B),
    secondary: Color(0xFFA67C52),
    onSurface: Color(0xFF3B3A36),
  ),
  ThemeModel(
    surface: Color(0xFFF5F5F5),
    primary: Color(0xFF6D6875),
    secondary: Color(0xFFFFB4A2),
    onSurface: Color(0xFF2D2D2D),
  ),
  ThemeModel(
    surface: Color(0xFFF0F8FF),
    primary: Color(0xFFA2C7E5),
    secondary: Color(0xFF89B0AE),
    onSurface: Color(0xFF2F3E46),
  ),
];

I'll show a list and they can chose one that will save a number like chosenTheme now i have a ThemeData like this

ThemeData myTheme = ThemeData(
  fontFamily: 'estedad',
  useMaterial3: true,
  //brightness: chosenTheme <= 2 ? Brightness.light : Brightness.dark,
  colorScheme:
      chosenTheme <= 2
          ? ColorScheme.light(
            surface: cards[chosenTheme].themes.surface,
            primary: cards[chosenTheme].themes.primary,
            secondary: cards[chosenTheme].themes.secondary,
            onSurface: cards[chosenTheme].themes.onSurface,
          )
          : ColorScheme.dark(
            surface: cards[chosenTheme].themes.surface,
            primary: cards[chosenTheme].themes.primary,
            secondary: cards[chosenTheme].themes.secondary,
            onSurface: cards[chosenTheme].themes.onSurface,
          ),
);

how can i set this as apps default theme in a theme provider?


Solution

  • Create a ThemeProvider class:

    import 'package:provider/provider.dart';
    
    class ThemeProvider with ChangeNotifier {
      int _chosenTheme = 0; // default theme
    
      int get chosenTheme => _chosenTheme;
    
      set chosenTheme(int value) {
        _chosenTheme = value;
        notifyListeners();
      }
    
      ThemeData get themeData {
        final theme = themes[_chosenTheme]; // import themes list
    
        return ThemeData(
          fontFamily: 'estedad',
          useMaterial3: true,
          colorScheme:
              _chosenTheme <= 2
                  ? ColorScheme.light(
                    surface: theme.surface,
                    primary: theme.primary,
                    secondary: theme.secondary,
                    onSurface: theme.onSurface,
                  )
                  : ColorScheme.dark(
                    surface: theme.surface,
                    primary: theme.primary,
                    secondary: theme.secondary,
                    onSurface: theme.onSurface,
                  ),
        );
      }
    }
    

    Use ThemeProvider's Consumer inside MyApp Widget and provide themeData to MaterialApp:

    import 'package:flutter/material.dart';
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Consumer<ThemeProvider>(
          builder: (context, themeProvider, _) {
            return MaterialApp(
              debugShowCheckedModeBanner: false,
              title: 'Themed App',
              theme: themeProvider.themeData,
              home: const HomeScreen(),
            );
          },
        );
      }
    }
    

    Create a List to update selected theme:

    class HomeScreen extends StatelessWidget {
      const HomeScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
        final themeProvider = Provider.of<ThemeProvider>(context);
    
        return Scaffold(
          appBar: AppBar(title: const Text("Choose a Theme")),
          body: ListView.builder(
            itemCount: themes.length,
            itemBuilder: (context, index) {
              final theme = themes[index];
              return ListTile(
                title: Text("Theme ${index + 1}"),
                tileColor: theme.surface,
                textColor: theme.onSurface,
                onTap: () {
                  themeProvider.chosenTheme = index;
                },
              );
            },
          ),
        );
      }
    }
    

    Now, Whenever theme is updated by the user it will update the widget tree with the new themeData. Use SharedPreferences to persist the chosenTheme in ThemeProvider.