Sytuacja kobiet w IT w 2024 roku
4.07.20193 min
Dane Mackier

Dane MackierFlutter ConsultantMDK Studio

Jak zbudować menadżera motywów we Flutterze

Sprawdź, jak krok po kroku stworzyć menadżera motywów we Flutterze dzięki ThemeManager.

Jak zbudować menadżera motywów we Flutterze

W tym poradniku zbudujemy prostego menadżer motywów, by móc zrobić coś takiego:

Przyjrzymy się jak zmienić kolor paska stanu, jak również całego motywu za pomocą flutter_statusbarcolor i provider. Zacznijmy od zainstalowania pakietów.

flutter_statusbarcolor: any
provider: ^3.0.0


Następnie możemy stworzyć HomeView, który wyświetli nasze zmiany w motywach.

class HomeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
floatingActionButton: FloatingActionButton(
onPressed: () {

},
));
}
}

Menedżer Motywów

Zalecam, aby odpowiedzialności obiektów były jasno zdefiniowane i aby Twój kod to odzwierciedlał. W naszym przypadku odpowiedzialność za zmianę motywów będzie spoczywać na ThemeManager. UI będzie po prostu używało motywu i ustawiało go bez wiedzy o zmianach jakie w nim zaszły. Nasz menedżer motywów będzie miał predefiniowaną listę availableThemes, jak również kontroler, w którym będziemy wyświetlać nowy motyw gdy zostanie ustawiony. Wyeksponujemy również strumień kontrolera poprzez właściwość publiczną.

class ThemeManager {
StreamController<ThemeData> _themeController = StreamController<ThemeData>();

List<ThemeData> _availableThemes = [
ThemeData(backgroundColor: Colors.red, accentColor: Colors.blue),
ThemeData(backgroundColor: Colors.green, accentColor: Colors.yellow),
ThemeData(backgroundColor: Colors.purple, accentColor: Colors.pink),
ThemeData(backgroundColor: Colors.blue, accentColor: Colors.red),
];

Stream<ThemeData> get theme => _themeController.stream;
}

Aktualizacja koloru paska stanu (StatusBar)

Zmiana motywu będzie obejmowała aktualizację koloru paska stanu, więc zaimplementujemy to jako oddzielną funkcję, którą wywołamy podczas zmiany naszego motywu.

Future _updateStatusBarColor(ThemeData themeToApply) async {
// Set status bar color
await FlutterStatusbarcolor.setStatusBarColor(themeToApply.accentColor);
// Check the constrast between the colors and set the status bar icons colors to white or dark

if (useWhiteForeground(themeToApply.accentColor)) {
FlutterStatusbarcolor.setStatusBarWhiteForeground(true);
} else {
FlutterStatusbarcolor.setStatusBarWhiteForeground(false);
}
}


Tutaj ustawiamy StatusBarColor na accentColor motywu. Dodatkowo upewniamy się, że ikony paska stanu są nadal widoczne, więc sprawdzamy kontrast za pomocą useWhiteForeground i ustawiamy ikony na biało lub czarno.

Aktualizacja motywu

Aby zmienić motyw, będziemy po prostu śledzić indeks currentTheme i będziemy inkrementować go w funkcji. Następnie użyjemy nowego indeksu, aby uzyskać motyw i dodać go do kontrolera.

int _currentTheme = 0;

...

Future changeTheme() async {
_currentTheme++;
if (_currentTheme >= _availableThemes.length) {
_currentTheme = 0;
}

// Get the theme to apply
var themeToApply = _availableThemes[_currentTheme];

// Update status bar color
await _updateStatusBarColor(themeToApply);
// Broadcast new theme
_themeController.add(themeToApply);
}

Dostarczenie motywu

Aby przenieść motyw do aplikacji i sprawić, że będzie automatycznie aktualizowany, skorzystamy z Providera. Zaczniemy od opakowania naszego MaterialApp w MultiProvider i dostarczenia ThemeManager jako providera, a następnie Theme jako StreamProvider.

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider.value(value: ThemeManager()),
StreamProvider<ThemeData>(
builder: (context) =>
Provider.of<ThemeManager>(context, listen: false).theme)
],
child: MaterialApp(
title: 'Theme Manager Demo',
home: HomeView(),
));
}
}


Tutaj rejestrujemy ThemeManager jako Provider. Następnie wysyłamy żądanie do providera o ThemeManagera w builderze StreamProvider i zwracamy strumień ThemeData. Mówimy również StreamProvider, aby nie nasłuchiwał aktualizacji z ThemeManagera. Jeśli używasz get_it do wstrzykiwania zależności, to będzie to wyglądać tak.

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<ThemeData>(builder: (context) => locator<ThemeManager>().theme)
],
child: MaterialApp(
title: 'Theme Manager Demo',
home: HomeView(),
));
}
}


Następnie musimy się upewnić, że gdy ThemeData się zmieni, zaktualizujemy nasz MaterialApp o nowy motyw. W tym celu opakujemy nasz MaterialApp w Konsumenta typu ThemeData i przekażemy motyw do naszej właściwości związanej z motywem w naszej aplikacji.

Widget build(BuildContext context) {
return MultiProvider(
...
child: Consumer<ThemeData>(
builder: (context, theme, child) => MaterialApp(
title: 'Theme Manager Demo',
theme: theme,
home: HomeView(),
)),
);
}


I ostatnią rzeczą, jaką musimy zrobić, jest wywołanie funkcji changeTheme w naszym menedżerze, gdy w HomeView zostanie naciśnięty przycisk FloatingActionButton.

class HomeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<ThemeManager>(context).changeTheme();
},
),
);
}
}

Podsumowanie

I to powinno wystarczyć. Należy dołożyć wszelkich starań, aby odpowiedzialności były rozdzielone i jasno zdefiniowane. W przypadku UI pokazywany jest tylko kolor zapewniony przez motyw. ThemeManager jest odpowiedzialny za aktualizację do nowego motywu, wykonywanie wszystkich obliczeń (w tym przykładzie jest ich niewiele), a następnie wyświetlanie nowego motywu. Reszta powinna być obsługiwana przez architekturę, w tym przypadku provider uaktualni motyw, który wyśle żądania do wszystkich konsumentów, zależnych od ThemeData, co doprowadzi do ich przebudowania.


Oryginał tekstu w języku angielskim przeczytasz tutaj.

<p>Loading...</p>