Notice
Recent Posts
Recent Comments
Link
«   2025/06   »
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
more
Archives
Today
Total
관리 메뉴

Plog

Flutter 카운터 앱 Steam -> Bloc 본문

Mobile/Flutter

Flutter 카운터 앱 Steam -> Bloc

풍중현 2020. 2. 16. 19:28

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_infinite_scroll_bloc/counter_page.dart';
import 'package:flutter_infinite_scroll_bloc/increment_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',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: BlocProvider<IncrementBloc>(
        bloc: IncrementBloc(),
        child: CounterPage(),
      )
    );
  }
}

counter_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_infinite_scroll_bloc/increment_bloc.dart';
class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final IncrementBloc bloc = BlocProvider.of<IncrementBloc>(context);
    return Scaffold(
      appBar: AppBar(title: Text('Bloc Counter App')),
      body: Center(
        child: StreamBuilder<int>(
          stream: bloc.outCounter,
          initialData: 0,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            return Text('${snapshot.hasData ? snapshot.data : 0}');
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          bloc.incrementCounter.add(null);
        }
      ),
    );
  }
}

increment_bloc.dart

import 'dart:async';

import 'package:flutter/cupertino.dart';

// Bloc 클래스
class IncrementBloc implements BlocBase {
  int _counter;

  // 카운터 출력을 위한 스트림을 제어하는 controller, sink, stream
  StreamController<int> _counterController = StreamController<int>();
  StreamSink<int> get _inAdd => _counterController.sink;
  Stream<int> get outCounter => _counterController.stream;

  // floating action button 이벤트를 제어하는 스트림 컨트롤러
  // floating action button을 누르면 _counterContoller.sink로
  // 1증가시킨 cohnter를 전달한다.
  StreamController _actionController = StreamController();
  StreamSink get incrementCounter => _actionController.sink;
  
  IncrementBloc() {
    _counter = 0;
    _actionController.stream.listen(_handleLogic);
  }
  @override
  void dispose() {
    _actionController.close();
    _counterController.close();
  }
  
  void _handleLogic(data) {
    _counter = _counter + 1;
    _inAdd.add(_counter);
  }
}

// Bloc 구현을 위한 추상 클래스
abstract class BlocBase {
  void dispose();
}

/// BlocProvider
/// 하위 위젯에서도 Bloc에 접근해줄 수 있게한다.
/// build(BuildContext context) 안에서
/// final IncrementBloc bloc = BlocProvider.of<IncrementBloc>(context);
class BlocProvider<T extends BlocBase> extends StatefulWidget {
  BlocProvider({
    Key key,
    @required this.child,
    @required this.bloc,
  }) : super(key: key);
  
  final T bloc;
  final Widget child;
  
  @override
  State<StatefulWidget> createState() => _BlocProviderState();
  
  static T of<T extends BlocBase>(BuildContext context) {
    BlocProvider<T> provider = context.findAncestorWidgetOfExactType<BlocProvider<T>>();
    return provider.bloc;
  }
}

class _BlocProviderState<T> extends State<BlocProvider<BlocBase>> {
  @override
  void dispose() {
    // TODO: implement dispose
    widget.bloc.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return widget.child;
  }
}