Flutter bloc – простой пример. Переключение цвета
обновлено: 08.12.2020
- реализация bloc во flutter без дополнительных библиотек, на потоках (stream) – смотрите пример приложения;
- базовая библиотека bloc – https://pub.dev/packages/bloc;
- flutter_bloc – https://pub.dev/packages/flutter_bloc – мощная и наиболее распространенная библиотека во flutter. Эту библиотеку мы и разберем в этом посте.
Полезные ссылки:
- документация на bloclibrary.dev
- введение в реактивное программирование на хабре
- вступление в реактивное программирование на хабре
Пример переключения цвета на flutter_bloc
Код рассматриваемого проекта можно посмотреть тут.
Мы создаем файл color_bloc.dart в котором мы перечисляем события по нажатию на кнопке: У нас их 2 – event_red и event_green. Эти значения события мы запишем в тип enum {}
Общая схема взаимодействия следующая:
обязательно объявить свой класс (в данном случае ColorBloc), отнаследованный от Bloc
в котором переопределить:
- метод initialState, который должен возвращать state
- метод mapEventToState, принимает событие. метод вызывается, всякий раз, когда добавляется событие. Конвертирует данное событие в новое состояние и возврает его в поток.
В виджете представления:
-BlocProvider
//виджет, который предоставляет bloc дочерним элементам через _bloc = BlocProvider.of(context)
в параметре create возвращаем наш объявленный ColorBloc
-- BlocBuilder
виджет, который содержит в себе контент, который нужно перерисовать.
в параметре builder указываем функцию, которая принимает контекст и State, в данном случае мы назанчили ему имя - currentColor.
по клику на кнопку _bloc.add(ColorsEvent.event_green) - добавляем событие в наш блок.
color_bloc.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
enum ColorEvent {event_red, event_green}
//ColocBloc будет принимать ColorEvent в качестве входного и выходного типа Color
class ColorBloc extends Bloc {
Color _color = Colors.red;
@override
Color get initialState => Colors.red;
@override
Stream mapEventToState(ColorEvent event) async* {
// async* - означает, что мы работаем с потоком
//бизнес логика приложения
_color = (event == ColorEvent.event_red) ? Colors.red : Colors.green;
yield _color; // добавляем значение в выходной поток
//yield - работает с потоком, добавляет значение в выходной поток. Но в отличие от return - не прекращает работу метода
}
}
main.dart
import 'package:bloc_example/color_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: BlocProvider(
//!!! BlocProvider - виджет,
//который предоставляет bloc дочерним элементам через BlocProvider.of(context).
//может быть предоставлен нескольким виджетам в поддереве.
create: (context) => ColorBloc(),
child: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
// при использовании flutter_bloc нам не нужно закрывать потоки(в отличие от bloc) и поэтому мы используем StatelessWidget.
//Данная библиотека делает это автоматически
@override
Widget build(BuildContext context) {
// ignore: close_sinks
ColorBloc _bloc = BlocProvider.of(context); //!!!
return Scaffold(
appBar: AppBar(
title: Text('BLoC with flutter_bloc'),
centerTitle: true,
),
body: Center(
//на вход: блок ColorBloc. на выход Сolor
child: BlocBuilder(
//!!! переписовка контента в ответ на новые состояния
// bloc - необязательный параметр. для чего???
builder: (context, currentColor) => AnimatedContainer( //currentColor !!!!!
height: 100,
width: 100,
color: currentColor,
duration: Duration(milliseconds: 500),
),
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
_bloc.add(ColorEvent.event_red); //!!!
},
),
SizedBox(width: 10),
FloatingActionButton(
backgroundColor: Colors.green,
onPressed: () {
_bloc.add(ColorEvent.event_green); //!!!
},
),
],
),
);
}
}
Demo: