๐Ÿ’ป ๊ฐœ๋ฐœ/Flutter

[Flutter] BLoC ํŒจํ„ด์œผ๋กœ ์ž๋™ ๋กœ๊ทธ์ธ, Splash Screen ๊ตฌํ˜„ํ•˜๊ธฐ - 1

2022. 7. 26. 23:51

๋ธ”๋กœ๊ทธ ๋‚ด์˜ ๊ฒŒ์‹œ๋ฌผ์€ PC ๋ฒ„์ „์— ์ตœ์ ํ™” ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

์˜ค๋Š˜์€ ํ”Œ๋Ÿฌํ„ฐ์—์„œ ์ž๋™ ๋กœ๊ทธ์ธ์™€ Splash Screen์„ ๊ตฌํ˜„ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ž๋™ ๋กœ๊ทธ์ธ์€ ์•ฑ ๊ฐœ๋ฐœ์„ ์ ‘ํ•ด๋ดค๋‹ค๋ฉด ํ•œ ๋ฒˆ์ฏค์€ ๊ตฌํ˜„ํ•ด๋ดค์„ ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. SharedPreference๋ฅผ ํ™œ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์˜ค๋Š˜์€ ์กฐ๊ธˆ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ ‘๊ทผํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ BLoC๋ฅผ ํ†ตํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ์š”, BLoC๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™ ๋กœ๊ทธ์ธ๊ณผ Splash Screen์„ ํ•˜๋‚˜์˜ ๋กœ์ง์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ๋ฒˆ ์‹œ์ž‘ํ•ด๋ณด์ฃ .

 

๋ฐ”๋กœ BLoC๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด์˜ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ณ  BLoC๋กœ ๋ฆฌํŽ™ํ† ๋งํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์™€ ์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ค ์‹์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š”์ง€๊ฐ€ ์ค‘์š”ํ•˜๋‹ˆ๊นŒ์š”.

 

์ž๋™ ๋กœ๊ทธ์ธ

์•ž์„œ ๋ง์”€๋“œ๋ฆฐ ๊ฒƒ์ฒ˜๋Ÿผ SharedPreference๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

shared_preferences | Flutter Package

Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.

pub.dev

ํ˜น์€ ๋ณด์•ˆ์— ์ข€ ๋” ์‹ ๊ฒฝ ์“ฐ๊ณ  ์‹ถ๋‹ค๋ฉด SecureSharedPreference๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. 

 

secure_shared_preferences | Flutter Package

Simple to use yet powerful package to encypt shared preferences in android and UserDefaults in iOS.

pub.dev

 

๊ตฌํ˜„์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ธ์ฆ(๋กœ๊ทธ์ธ)์— ์„ฑ๊ณตํ•˜๋ฉด SharedPreference์— ํŠน์ • ๊ฐ’(ํ† ํฐ)์„ ์ €์žฅํ•˜๊ณ  ์•ฑ์„ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ์ฒ˜์Œ ๋กœ๋“œ๋˜๋Š” ํด๋ž˜์Šค(ํŽ˜์ด์ง€)์—์„œ didChangeDependencies๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์„œ SharedPreference์— ์ €์žฅ๋œ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ณ  ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

 

๋ง๋กœ ๋ณด๋‹ˆ๊นŒ ๋ณต์žกํ•ด ๋ณด์ด๋„ค์š”. ์ฝ”๋“œ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ด๋ณด๋„๋ก ํ•˜์ฃ . ์‹ค์ œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์ฒ˜๋Ÿผ TextField๋Š” ์“ฐ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. FloatingActionButton์œผ๋กœ ๋กœ๊ทธ์ธ์„ ๋Œ€์‹ ํ•ฉ๋‹ˆ๋‹ค.

 

Main ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isAuth = false;

  @override
  void didChangeDependencies() async {
  // SharedPreference์— ์ €์žฅ๋œ ํ† ํฐ์ด ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธ
    final token = await SharedPreferManager().getSharedPreference();
    if (token != "Not Auth") {
      _isAuth = true;
    }
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _isAuth ? const HomeScreen() : const LoginScreen(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await SharedPreferManager()
              .setSharedPreference("codokodo is authenticate");
        },
        child: const Icon(Icons.login),
      ),
    );
  }
}

ํ”Œ๋Ÿฌํ„ฐ๊ฐ€ ๊ธฐ๋ณธ ์ œ๊ณตํ•ด์ฃผ๋Š” ์Šค์ผˆ๋ ˆํ†ค ์ฝ”๋“œ ์œ„์—์„œ ์ž‘์—…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•ž์„œ ๋ง์”€๋“œ๋ฆฐ ๊ฒƒ์ฒ˜๋Ÿผ SharedPreference์— ์ €์žฅ๋œ ํ† ํฐ์ด ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ํ† ํฐ์ด ์ €์žฅ๋˜์–ด ์žˆ์œผ๋ฉด _isAuth๋ฅผ true๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์œ„์ ฏ์„ ๋ Œ๋”๋งํ•  ๋•Œ _isAuth์˜ ๊ฐ’์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋˜ํ•œ TextField๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  FloatingActionButton์„ ํด๋ฆญํ•˜๋ฉด SharedPreference์— ํŠน์ •ํ•œ ๋ฌธ์ž์—ด(ํ† ํฐ์ด๋ผ๊ณ  ๊ฐ€์ •)์„ ์ €์žฅํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

Home Screen๊ณผ Login Screen๋Š” ๊ฐ๊ฐ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ดํ›„์— ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด๊ณผ ์ด์ „์— ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text(
        "์‚ฌ์šฉ์ž ์ธ์ฆ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 18,
        ),
      ),
    );
  }
}
import 'package:flutter/material.dart';

class LoginScreen extends StatefulWidget {
  const LoginScreen({Key? key}) : super(key: key);

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text(
        "๋กœ๊ทธ์ธ์„ ์ง„ํ–‰ํ•ด์ฃผ์„ธ์š”.",
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 18,
        ),
      ),
    );
  }
}

 

๋ณ„๋„๋กœ ์ •์˜ํ•œ SharedPreferManager์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. Singleton์œผ๋กœ ์ •์˜ํ•˜์˜€๊ณ  getter, setter์— ๋Œ€ํ•œ ๋กœ์ง๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. getter๋ฅผ ๋ณด๋ฉด key๋กœ ์ „๋‹ฌํ•œ auth์˜ value๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด Not Auth๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

import 'package:shared_preferences/shared_preferences.dart';

class SharedPreferManager {
  static final SharedPreferManager _instance = SharedPreferManager._internal();
  final Future<SharedPreferences> _manager = SharedPreferences.getInstance();

  SharedPreferManager._internal() {}

  factory SharedPreferManager() {
    return _instance;
  }

  Future<void> setSharedPreference(String token) async {
    final manager = await _manager;
    manager.setString("auth", token);
  }

  Future<String> getSharedPreference() async {
    final manager = await _manager;
    return manager.getString("auth") ?? "Not Auth";
  }
}

 

๊ตฌํ˜„์ด ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋นŒ๋“œ๋ฅผ ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์•ฑ์„ ์ฒ˜์Œ ์‹คํ–‰ํ–ˆ์„ ๋•Œ์—๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€(LoginScreen)๋กœ ์ด๋™ํ•˜์ง€๋งŒ FloatingActionButton์„ ํด๋ฆญํ•˜๊ณ  ์•ฑ์„ ์žฌ์‹คํ–‰ํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ธ์ฆ์— ์„ฑ๊ณตํ–ˆ๋‹ค๋Š” ๋ฉ”์ธ ํŽ˜์ด์ง€(HomeScreen)์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

์ข‹์€๋ฐ์š”? ๋ญ๊ฐ€ ๋ฌธ์ œ์ฃ ?

 

๋ฌธ์ œ์ 

๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„์„ ๋งˆ์ณค์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ญ”๊ฐ€ ์–ด์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ธ์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด ์•ฑ์„ ์žฌ์‹คํ–‰ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ง€๊ธˆ์€ ์•ฑ์„ ์žฌ์‹คํ–‰ํ•ด์•ผ์ง€๋งŒ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. didChangeDependencies์— Navigator ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ Home Screen์œผ๋กœ ์ด๋™ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋กœ๊ทธ์•„์›ƒ ์—ญ์‹œ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ Home Screen์—์„œ Login Screen์œผ๋กœ ์ด๋™ํ•˜๋Š” Navigator ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ Navigator๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜๋ฉด ํ™•์žฅ์„ฑ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. (์ฃผ๊ด€์ ์ธ ์˜๊ฒฌ์ž…๋‹ˆ๋‹ค.)

 

๊ฐ€๋ น Splash Screen์„ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณผ๊นŒ์š”? ์•ฑ์„ ์‹คํ–‰ํ•˜๋ฉด ๋จผ์ € Splash Screen๋ถ€ํ„ฐ ๋ณด์—ฌ์ง€๋Š”๋ฐ

[Splash Screen] SharedPreference ํ™•์ธ & ํ† ํฐ์ด ์ €์žฅ๋˜์–ด ์žˆ์ง€ ์•Š์Œ -> Navigator๋กœ Push -> [Login Screen] ์‚ฌ์šฉ์ž ์ธ์ฆ ์„ฑ๊ณต -> Navigator๋กœ Push -> [Home Screen]

๋ฒŒ์จ ๋‘ ๋ฒˆ์˜ Push๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฐ ํŽ˜์ด์ง€๊ฐ€ ์ข…์†์ ์œผ๋กœ ๊ตฌํ˜„๋œ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ BLoC์œผ๋กœ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. (์ง€๊ธˆ๊นŒ์ง€ ์„œ๋ก ์ธ๊ฐ€์š”?) BLoC๋ฅผ ์ ์šฉํ•˜๋ฉด ํ•˜๋‚˜์˜ ๋กœ์ง์œผ๋กœ ๋‘ ๊ฐœ์˜ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์—์„œ ๋ชจ๋‘ ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

 

์šฐ์„  BLoC์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ €๋„ ์ธํ„ด์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ BLoC์— ๋Œ€ํ•ด ๋ฐฐ์šฐ๊ณ  ์žˆ๋Š” ๋‹จ๊ณ„๋ผ ์•„์ง ๋งŽ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค. ๋””์ž์ธ ํŒจํ„ด์ด๋‚˜ ์ƒํƒœ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ์ง€์‹์ด ์žˆ์œผ์‹œ๋ฉด ์ดํ•ด๊ฐ€ ๋น ๋ฅด์‹ค ๊ฒ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด UI์— Data๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” Presention Layer์™€ Data๋ฅผ ๊ฐ€๊ณตํ•˜๋Š” Business Logic์„ ๋ณ„๋„๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์œผ๋กœ MVVM๊ณผ ์ƒ๋‹นํžˆ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. 

 

BLoC๋Š” Event, State, BLoC๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. 3๊ฐœ์˜ ํด๋ž˜์Šค๋กœ ๊ตฌ๋ถ„๋œ๋‹ค๊ณ  ์ดํ•ดํ•˜์‹œ๋Š”๊ฒŒ ์ข‹๊ฒ ๋„ค์š”. ๊ฐ๊ฐ์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ ๊ฒŒ์‹œ๊ธ€๋กœ ์ฐพ์•„์˜ค๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•˜๋‹จ์— ๊ด€๋ จ ์ž๋ฃŒ๋ฅผ ์ฒจ๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

flutter_bloc | Flutter Package

Flutter Widgets that make it easy to implement the BLoC (Business Logic Component) design pattern. Built to be used with the bloc state management package.

pub.dev

 

Flutter bloc for beginners

What is flutter bloc?

medium.com

 

Flutter: BlocBuilder vs BlocConsumer vs BlocListener

You can find the Spanish version here ๐Ÿ‘‡

ppantaleon.medium.com

 

https://booiljung.github.io/technical_articles/flutter/state_management/architecture_your_flutter_project_using_bloc_pattern.html

Top BLOC ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ Flutter ํ”„๋กœ์ ํŠธ ์•„ํ‚คํ…์ณ ์„ค๊ณ„ ์›๋ฌธ: Architect your Flutter project using BLOC pattern ์—ฌ๋Ÿฌ๋ถ„ ์•ˆ๋…•ํ•˜์„ธ์š”! ์ €๋Š” Flutter์— ๊ด€ํ•œ ์ƒˆ๋กœ์šด ๊ธ€์„ ๊ฐ€์ง€๊ณ  ์™”์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” โ€œFlutter ํ”„๋กœ์ 

booiljung.github.io

 

์ €์ž‘์žํ‘œ์‹œ ๋น„์˜๋ฆฌ ๋ณ€๊ฒฝ๊ธˆ์ง€ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'๐Ÿ’ป ๊ฐœ๋ฐœ > Flutter' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Flutter] ModalBottomSheet๊ฐ€ ํ‚ค๋ณด๋“œ์— ์˜ํ•ด ๊ฐ€๋ ค์ง€๋Š” ํ˜„์ƒ  (0) 2022.08.09
[Flutter / Dart] What is Equatable?  (0) 2022.08.06
[Flutter / Dart] What is Singleton?  (0) 2022.07.21
[Flutter] SingleChildScrollView, ListView, ListView.bulider  (1) 2021.08.18
4. Column, Row, Expanded  (0) 2021.08.18
'๐Ÿ’ป ๊ฐœ๋ฐœ/Flutter' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [Flutter] ModalBottomSheet๊ฐ€ ํ‚ค๋ณด๋“œ์— ์˜ํ•ด ๊ฐ€๋ ค์ง€๋Š” ํ˜„์ƒ
  • [Flutter / Dart] What is Equatable?
  • [Flutter / Dart] What is Singleton?
  • [Flutter] SingleChildScrollView, ListView, ListView.bulider
kodo_o
kodo_o
iOS ๊ฟ€์žผ!
kodo_o
๐ŸŽ๐Ÿ
kodo_o
์ „์ฒด
์˜ค๋Š˜
์–ด์ œ
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (149)
    • ๐Ÿ”จ ํ”„๋กœ์ ํŠธ (0)
      • TP 1 (0)
      • WhiteHCCTV (0)
      • FootPrint (0)
    • ๐Ÿ’ป ๊ฐœ๋ฐœ (63)
      • iOS (30)
      • Android (6)
      • Kotlin (4)
      • Flutter (9)
      • Node.js (5)
      • Architecture (1)
      • ์˜ค๋Š˜์˜ ์‚ฝ์งˆ (7)
      • ์—๋Ÿฌ์™€์˜ ๋™์นจ (1)
    • โœ๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (6)
      • Graph (6)
      • String (0)
      • Sort (0)
    • โœ๏ธ ์ฝ”ํ…Œ ์ค€๋น„ (44)
      • Math (1)
      • Implementation (3)
      • String (3)
      • Brute Force (5)
      • Back Tracking (7)
      • Greedy (0)
      • Dynamic Programming (13)
      • Binary Search (1)
      • DFS, BFS (5)
      • Shortest Path (2)
      • Two Pointer (4)
      • MST (0)
    • ๐Ÿ“š CS (6)
      • Operating System (6)
    • โ›น๏ธ ๋ผ์ดํ”„ (30)
      • 2020 ๊ฒจ์šธ๋ฐฉํ•™ ๋ชจ๊ฐ์ฝ”(๊ฐœ์ธ) (12)
      • 2021 ์—ฌ๋ฆ„๋ฐฉํ•™ ๋ชจ๊ฐ์ฝ”(๊ฐœ์ธ) (6)
      • ์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ (1)
      • ํšŒ๊ณ  (10)

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • ํ™ˆ
  • ๊นƒํ—ˆ๋ธŒ

์ธ๊ธฐ ๊ธ€

์ตœ๊ทผ ๊ธ€

์ตœ๊ทผ ๋Œ“๊ธ€

hELLO ยท Designed By ์ •์ƒ์šฐ.
kodo_o
[Flutter] BLoC ํŒจํ„ด์œผ๋กœ ์ž๋™ ๋กœ๊ทธ์ธ, Splash Screen ๊ตฌํ˜„ํ•˜๊ธฐ - 1
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”

๋‹จ์ถ•ํ‚ค

๋‚ด ๋ธ”๋กœ๊ทธ

๋‚ด ๋ธ”๋กœ๊ทธ - ๊ด€๋ฆฌ์ž ํ™ˆ ์ „ํ™˜
Q
Q
์ƒˆ ๊ธ€ ์“ฐ๊ธฐ
W
W

๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€

๊ธ€ ์ˆ˜์ • (๊ถŒํ•œ ์žˆ๋Š” ๊ฒฝ์šฐ)
E
E
๋Œ“๊ธ€ ์˜์—ญ์œผ๋กœ ์ด๋™
C
C

๋ชจ๋“  ์˜์—ญ

์ด ํŽ˜์ด์ง€์˜ URL ๋ณต์‚ฌ
S
S
๋งจ ์œ„๋กœ ์ด๋™
T
T
ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ ์ด๋™
H
H
๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด
Shift + /
โ‡ง + /

* ๋‹จ์ถ•ํ‚ค๋Š” ํ•œ๊ธ€/์˜๋ฌธ ๋Œ€์†Œ๋ฌธ์ž๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ‹ฐ์Šคํ† ๋ฆฌ ๊ธฐ๋ณธ ๋„๋ฉ”์ธ์—์„œ๋งŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.