반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- uint16array
- Excel
- Babel standalone
- Completer
- uint8array
- typescript
- jszip
- web track
- react
- Three js
- identifierForVender
- swagger-typescript-api
- Flutter
- FirebaseAnalytics
- Redux
- KakaoMap
- code editor
- webrtc
- androidId
- REST API
- methodChannel
- userevent_tracker
- Prism.js
- Image Resize typescript
- RouteObserver
- Three-fiber
- Raycasting
- babel
- node
- Game js
Archives
- Today
- Total
Never give up
Flutter - Bloc todo example 본문
반응형
보통 상태관리 예제로 카운터 예제를 많이 하는데
다른 곳에 적용하기가 조금 어려운 분들을 위해 간단한 todo list를 만들어봤습니다
구조는 저번과 동일하며 데이터타입(State부분)과 이벤트 처리만 조금 변경되니
예제를 보면 충분히 이해될거라 생각됩니다
State
class ListState {
List<ListItem> list = [];
ListState(this.list);
ListState update(List<ListItem> list) => ListState(list);
}
ListItem
class ListItem {
String title = '', desc = '';
DateTime date = DateTime.now();
int isChecked = 0;
ListItem({this.title, this.desc});
void toggleCheck() {
if (getIsChecked) {
isChecked = 0;
} else {
isChecked = 1;
}
}
bool get getIsChecked => (isChecked == 1);
String get getDate => DateFormat('yyyy.MM.dd').format(date);
}
Event
abstract class ListEvent{}
class AddEvent extends ListEvent{
final ListItem item;
AddEvent(this.item);
}
class DeleteEvent extends ListEvent{
final int index;
DeleteEvent(this.index);
}
class UpdateEvent extends ListEvent{
final int index;
final ListItem item;
UpdateEvent(this.index, this.item);
}
class ToggleEvent extends ListEvent{
final int index;
ToggleEvent(this.index);
}
bloc
class ListBloc extends Bloc<ListEvent, ListState> {
ListBloc() : super(ListState([]));
@override
Stream<ListState> mapEventToState(ListEvent event) async* {
if (event is AddEvent) {
yield* _add(event.item);
} else if (event is DeleteEvent) {
yield* _delete(event.index);
} else if (event is UpdateEvent) {
yield* _update(index: event.index, item: event.item);
} else if (event is ToggleEvent) {
yield* _toggle(event.index);
}
}
Stream<ListState> _add(ListItem item) async* {
List<ListItem> list = state.list;
list.add(item);
yield state.update(list);
}
Stream<ListState> _delete(int index) async* {
List<ListItem> list = state.list;
list.removeAt(index);
yield state.update(list);
}
Stream<ListState> _update({int index, ListItem item}) async* {
List<ListItem> list = state.list;
list[index] = item;
yield state.update(list);
}
Stream<ListState> _toggle(int index) async* {
List<ListItem> list = state.list;
list[index].toggleCheck();
yield state.update(list);
}
}
Main
class BlocListExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<ListBloc>(create: (_) => ListBloc(), child: BlocMain());
}
}
class BlocMain extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Bloc list example')),
body: BlocBuilder<ListBloc, ListState>(builder: (_, state) {
return ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
itemCount: state.list.length,
itemBuilder: (_, index) {
var item = state.list[index];
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
child: ExpansionTile(
leading: Checkbox(
value: item.getIsChecked,
onChanged: (value) =>
context.read<ListBloc>().add(ToggleEvent(index))),
title: Text(item.title),
children: [
ListTile(
title: Text(item.desc), trailing: Text(item.getDate)),
Row(mainAxisAlignment: MainAxisAlignment.end, children: [
FlatButton(
onPressed: () => context
.read<ListBloc>()
.add(DeleteEvent(index)),
child: Text('Delete')),
FlatButton(
onPressed: () => _dialog(
context: context, isEdit: true, index: index),
child: Text('Edit')),
])
],
));
});
}),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.edit), onPressed: () => _dialog(context: context)),
);
}
void _dialog({BuildContext context, bool isEdit = false, int index}) {
String title = '', desc = '';
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text(isEdit ? 'Edit' : 'Add'),
content: Column(mainAxisSize: MainAxisSize.min, children: [
Divider(
color: Colors.grey,
),
Row(children: [
Text('Title : '),
Expanded(
child: TextField(
maxLines: 1,
decoration:
InputDecoration(border: UnderlineInputBorder()),
onChanged: (value) {
title = value;
}),
)
]),
Padding(
padding: const EdgeInsets.only(top: 8),
child: TextField(
maxLines: 3,
decoration: InputDecoration(border: OutlineInputBorder()),
onChanged: (value) {
desc = value;
},
),
)
]),
actions: [
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel')),
FlatButton(
onPressed: () {
if (isEdit) {
context.read<ListBloc>().add(UpdateEvent(
index, ListItem(title: title, desc: desc)));
} else {
context
.read<ListBloc>()
.add(AddEvent(ListItem(title: title, desc: desc)));
}
Navigator.pop(context);
},
child: Text('Confirm')),
],
));
}
}
먼저 State에 List를 선언해주고 이전과 동일하게 update를 통해 상태를 업데이트 해주고
이벤트에서는 해당 이벤트에 필요한 파라미터를 넣어줍니다
(예를들어 removeAt(index)인경우 index값이 필요하므로 int값을 주면 됩니다)
bloc에서는 event별로 메소드를 나눠주고 state의 list를 넣어주는데 크게 다른점은 없습니다
한줄로 정리해보면 "event에 따라 list가 변하게 되고 변화된 list를 stream을 통해 보내줍니다"
메인에서는 blocprovider안에서 발생하는 이벤트들 add, delete, edit, toggle를
context.read.add를 통해 event를 주고 blocbuilder안에서 event에 따라 state값이 변하게됩니다
반응형
'Flutter' 카테고리의 다른 글
Flutter 2.0 - Null safety에 대한 이해 (0) | 2021.03.06 |
---|---|
Flutter - 비동기처리의 이해 (0) | 2021.03.02 |
Flutter - How to use exntension with getting widget position (0) | 2021.02.07 |
Flutter - update previous screen with Navigator callback (0) | 2021.01.05 |
Flutter - PageView with TabBar and Indicator (0) | 2021.01.03 |
Comments