728x90
๋ฐ˜์‘ํ˜•
728x90

์ด์ œ Step 6 !!!

์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์•ฑ์€, next ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ด์ „์— ๋‚˜์™”๋˜ ๋‹จ์–ด๋ฅผ ๋ณผ ์ˆ˜ ์—†์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ด๋ฒˆ ๋‹จ๊ณ„์—์„œ๋Š” 'Like' ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ, ์›ํ•˜๋Š” ๋‹จ์–ด๋ฅผ ๊ธฐ์–ตํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

 

์ด๋ฒˆ ๋ชฉํ‘œ๋Š” ๋‹ค์Œ ํ™”๋ฉด๊ณผ ๊ฐ™๋‹ค.

์ด๋ฒˆ step์˜ ๋ชฉํ‘œ !!

 

Add the business logic

MyAppState ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž.

 

lib/main.dart

// ...

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();

  void getNext() {
    current = WordPair.random();
    notifyListeners();
  }

  // ↓ Add the code below.
  var favorites = <WordPair>[];

  void toggleFavorite() {
    if (favorites.contains(current)) {
      favorites.remove(current);
    } else {
      favorites.add(current);
    }
    notifyListeners();
  }
}

// ...
  • ์ง€๊ธˆ ์šฐ๋ฆฌ๋Š” favorites ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” property๋ฅผ MyAppState์— ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด๋‹ค. ์ด property๋Š” ๋นˆ ๋ฆฌ์ŠคํŠธ [] ๋กœ ์ดˆ๊ธฐํ™”๋œ๋‹ค.
  • ๋˜ํ•œ, generics๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชฉ๋ก์— ๋‹จ์–ด์Œ์ธ <WordPair>[]๋งŒ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์ •ํ•œ ๊ฒƒ์ด๋‹ค. ์ด๋Š” ์šฐ๋ฆฌ ์•ฑ์„ ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์„ ์ฃผ๋Š”๋ฐ, Dart๊ฐ€ WordPair ์ด์™ธ์˜ ๊ฒƒ์„ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์šฐ๋ฆฌ ์•ฑ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์กฐ์ฐจ ๊ฑฐ๋ถ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 
    ์ฆ‰, WordPair ์ด์™ธ์˜ ๊ฒƒ์€ ์ถ”๊ฐ€ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, favorites ๋ชฉ๋ก์„ ํ†ตํ•ด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฐœ์ฒด(ex. null)๊ฐ€ ์ˆจ๊ฒจ์งˆ ์ˆ˜ ์—†์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
    List ๋Œ€์‹  Set์„ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค. Set์€ []๊ฐ€ ์•„๋‹Œ, {}์„ ํ†ตํ•ด ํ‘œํ˜„ํ•œ๋‹ค.
  • ๋˜ํ•œ, toggleFavorite() ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Š” ๋งŒ์•ฝ favorites ๋ฆฌ์ŠคํŠธ์— ํ˜„์žฌ ๋‹จ์–ด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ์—†์• ๊ฑฐ๋‚˜, ๋งŒ์•ฝ ๋ฆฌ์ŠคํŠธ์— ์—†๋‹ค๋ฉด ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋‘ ๊ฒฝ์šฐ, ์ฝ”๋“œ๋Š” notifyListerners();๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

 

Add the button

์ด์ œ ์ข‹์•„์š” ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด์„œ 'Next' ๋ฒ„ํŠผ ์™ผ์ชฝ์— ๋งŒ๋“ค์–ด์ค„ ๊ฒƒ์ด๋‹ค. ๋ฒ„ํŠผ์„ Next ์˜†์— ๋‘๊ธฐ ์œ„ํ•ด์„œ๋Š” Row ์œ„์ ฏ์ด ํ•„์š”ํ•˜๋‹ค.

๋จผ์ € ํ˜„์žฌ ์กด์žฌํ•˜๋Š” ๋ฒ„ํŠผ์„ Row๋กœ ๊ฐ์‹ผ๋‹ค.

MyHomePage์˜ build()๋ฉ”์†Œ๋“œ๋กœ ๊ฐ€์„œ, ElevatedButton ์œ„์— ์ปค์„œ๋ฅผ ๋‘๊ณ  Refactor ๋ฉ”๋‰ด๋ฅผ ์—ด์–ด Wrap with Row๋ฅผ ์„ ํƒํ•œ๋‹ค.

 

์ด๋ฅผ ์ €์žฅํ•˜๋ฉด, Column์„ ์ ์šฉํ–ˆ์„ ๋•Œ์™€ ๋น„์Šทํ•˜๊ฒŒ children์ด ์™ผ์ชฝ์— ์น˜์šฐ์ ธ์ง„ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (Column์€ ์œ„๋กœ..!)

์ด๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋ชจ์–‘์œผ๋กœ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Column์—์„œ ํ•œ ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๊ฒŒ center๋ฅผ ๋งž์ถฐ์ฃผ๋ฉด ๋œ๋‹ค.

Row์—์„œ๋Š” mainAxisAlignment๋ฅผ ํ†ตํ•ด ๋งž์ถœ ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฅผ ์ ์šฉํ•œ ์ฝ”๋“œ์ด๋‹ค.

 

lib/main.dart

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            BigCard(pair: pair),
            SizedBox(height: 10),
            Row(
              mainAxisSize: MainAxisSize.min,   // ← Add this.
              children: [
                ElevatedButton(
                  onPressed: () {
                    appState.getNext();
                  },
                  child: Text('Next'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// ...

๋‹ค์‹œ Row๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „์œผ๋กœ ๋Œ์•„๊ฐ„ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ์„ผํ„ฐ๊ฐ€ ๋งž์ถฐ์ง„ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ, ์šฐ๋ฆฌ๋Š” Like button์„ ์ถ”๊ฐ€ํ•ด์„œ ์ด๋ฅผ toggleFavorites()์™€ ์—ฐ๊ฒฐํ•  ๊ฒƒ์ด๋‹ค.

์ด๋ฅผ ์œ„ํ•ด, ์ฝ”๋“œ๋žฉ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง์ ‘ ๋„์ „ํ•ด๋ณด๊ธธ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ๋‹ค.

๋ชจ๋‘ ์ง์ ‘ ํ•œ ๋ฒˆ ํ•ด๋ณด๊ธธ..!

  • MyHomePage์— ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ElevatedButton.icon()์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • build ๋ฉ”์†Œ๋“œ์˜ ๊ฐ€์žฅ ์œ— ๋ถ€๋ถ„์— word pair๊ฐ€ favorite์œผ๋กœ ์„ ํƒ๋๋Š”์ง€์˜ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ ์ ˆํ•œ icon์„ ์„ ํƒํ•œ๋‹ค.
  • SizedBox๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‘ ๋ฒ„ํŠผ ์‚ฌ์ด์˜ ์—ฌ๋ฐฑ์„ ๋‘”๋‹ค.

์ฝ”๋“œ๋žฉ์—์„œ ์ œ๊ณตํ•œ ์ฝ”๋“œ๋Š” ์ด๋Ÿฌํ•˜๋‹ค

 

lib/main.dart

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    // ↓ Add this.
    IconData icon;
    if (appState.favorites.contains(pair)) {
      icon = Icons.favorite;
    } else {
      icon = Icons.favorite_border;
    }

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            BigCard(pair: pair),
            SizedBox(height: 10),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [

                // ↓ And this.
                ElevatedButton.icon(
                  onPressed: () {
                    appState.toggleFavorite();
                  },
                  icon: Icon(icon),
                  label: Text('Like'),
                ),
                SizedBox(width: 10),

                ElevatedButton(
                  onPressed: () {
                    appState.getNext();
                  },
                  child: Text('Next'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// ...

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค!!

์ด์ œ step 6์ด ๋๋‚ฌ๋‹ค!!!

 

๋‹ค์Œ ์Šคํ…์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ข‹์•„์š” ํ•œ ๋‹จ์–ด๊ฐ€ ๋ฌด์—‡์ธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก ํ•  ์˜ˆ์ • !!

 

์ „์ฒด ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ•œ๋‹ค !

 

lib/main.dart

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyAppState(),
      child: MaterialApp(
        title: 'Namer App',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        ),
        home: MyHomePage(),
      ),
    );
  }
}

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();

  void getNext() {
    current = WordPair.random();
    notifyListeners();
  }

  var favorites = <WordPair>[];

  void toggleFavorite() {
    if (favorites.contains(current)) {
      favorites.remove(current);
    } else {
      favorites.add(current);
    }
    notifyListeners();
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    IconData icon;
    if (appState.favorites.contains(pair)) {
      icon = Icons.favorite;
    } else {
      icon = Icons.favorite_border;
    }

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            BigCard(pair: pair),
            SizedBox(height: 10),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                ElevatedButton.icon(
                  onPressed: () {
                    appState.toggleFavorite();
                  },
                  icon: Icon(icon),
                  label: Text('Like'),
                ),
                SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () {
                    appState.getNext();
                  },
                  child: Text('Next'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class BigCard extends StatelessWidget {
  const BigCard({
    Key? key,
    required this.pair,
  }) : super(key: key);

  final WordPair pair;

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    var style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );

    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Text(
          pair.asLowerCase,
          style: style,
          semanticsLabel: pair.asPascalCase,
        ),
      ),
    );
  }
}
728x90
๋ฐ˜์‘ํ˜•
728x90
๋ฐ˜์‘ํ˜•
728x90

์ง€๋‚œ ์Šคํ…๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ์™”๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”์„ ๊ฒƒ์ด๋‹ค.

ํ•˜์ง€๋งŒ ๋ชจ๋‘ ๋Š๋ผ๋“ฏ, ํ˜„์žฌ๋Š” ํŒจ๋”ฉ๋„ ๋งž์ง€ ์•Š๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์ค‘์š”ํ•˜๊ฒŒ ๋ณด์—ฌ์ค˜์•ผ ํ•  ๋ฐ์ดํ„ฐ์ธ word๊ฐ€ ํ•œ ๋ˆˆ์— ๋“ค์–ด์˜ค์ง€ ์•Š๋Š”๋‹ค.

์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋Š๋ผ๊ธฐ์— ์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ, ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผํ•œ๋‹ค. 

 

๊ทธ๋ž˜์„œ ์ด๋ฒˆ ์Šคํ…์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์‹œ๊ฐ์ ์ธ ์š”์†Œ(๋””์ž์ธ) ์— ์กฐ๊ธˆ ์‹ ๊ฒฝ์„ ์จ๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

์ฝ”๋“œ๋žฉ์—์„œ ์ œ์‹œํ•œ ๋‹ค์Œ ์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” ์ด ์ด๋ฏธ์ง€์™€ ๊ฐ™๋‹ค.

์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ !!

 

Extract a widget

ํ˜„์žฌ ์šฐ๋ฆฌ ์ฝ”๋“œ์—์„œ๋Š” word pair๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜ํƒ€๋‚ด๊ณ  ์žˆ๋‹ค.

Text(appState.current.asLowerCase)

์ด ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ๋” ๋ณต์žกํ•˜๊ฒŒ ๋ฐ”๊ฟ”๋ณด๋ ค๊ณ  ํ•œ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ๋ณ„๋„์˜ ์œ„์ ฏ์œผ๋กœ ๋นผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค. 

์ด์ฒ˜๋Ÿผ UI์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์œ„์ ฏ์„ ๊ฐ–๋Š” ๊ฒƒ์€ Flutter์—์„œ ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ์ค‘์š”ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. 

(+ ๋‚ด ๊ฒฝํ—˜์— ๋น„์ถ”์–ด๋ณด๋ฉด, ์ด๋ฅผ ๋”ฐ๋กœ ์œ„์ ฏ์œผ๋กœ ๋นผ์„œ ๋งŒ๋“ค์–ด๋‘๋ฉด ๋‚˜์ค‘์— ๋˜ ์“ฐ์ผ ๋•Œ ๋‹ค์‹œ ์ฝ”๋“œ๋ฅผ ์งœ๊ฑฐ๋‚˜, ์ด์ „ ์ฝ”๋“œ๋ฅผ ์ฐพ์•„ ๋ณต๋ถ™ํ•˜๋Š” ์ผ์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ๋˜ํ•œ, ์ˆ˜์ •์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ๋„ ์‰ฝ๊ฒŒ ์ฐพ์•„์„œ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ž‘์€ ๋‹จ์œ„๋กœ ์œ„์ ฏ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค !!)

 

๋ฌผ๋ก  Flutter์—์„œ๋Š” ์œ„์ ฏ์„ extract ํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ๊ฐ€ ์žˆ์ง€๋งŒ, ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— extract๋˜๋Š”์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์—๋งŒ ์ ‘๊ทผํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ์šฐ๋ฆฌ ์ฝ”๋“œ๋ฅผ ์˜ˆ๋กœ ๋ณด๋ฉด, ํ˜„์žฌ appState์— ์ ‘์†ํ•˜์ง€๋งŒ, ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์ •๋ณด๋Š” ํ˜„์žฌ ๋‹จ์–ด ์Œ๋งŒ ์•Œ๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ ์ด์ œ  MyHomePage  ์œ„์ ฏ์˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”๊ฟ”๋ณด์ž..!!

 

lib/main.dart

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();  
    var pair = appState.current;                 // ← Add this.

    return Scaffold(
      body: Column(
        children: [
          Text('A random AWESOME idea:'),
          Text(pair.asLowerCase),                // ← Change to this.
          ElevatedButton(
            onPressed: () {
              appState.getNext();
            },
            child: Text('Next'),
          ),
        ],      // ← 7
      ),
    );
  }
}

// ...

์ด์ œ Text ์œ„์ ฏ์€ ๋”์ด์ƒ appState๋ฅผ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

 

๊ทธ๋ฆฌ๊ตฌ, ์ด์ œ Refactor ๋ฉ”๋‰ด๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์œ„์ ฏ extract๋ฅผ ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

1. refactor ํ•˜๊ณ  ์‹ถ์€ ์œ„์ ฏ์—์„œ ์šฐํด๋ฆญ -> Refactor ๋ฉ”๋‰ด๋ฅผ ์„ ํƒ -> "BigCard" ์ž…๋ ฅ -> ์—”ํ„ฐ

 

2. Move your cursor to the piece code you want to refactor (Text, in this case), and press Ctrl+. (Win/Linux) or Cmd+. (Mac). (๋‚˜๋งŒ ํ—ท๊ฐˆ๋ ธ๋‚˜.. Cmd๋ž‘ .์„ ๊ฐ™์ด ๋ˆ„๋ฅด๋ฉด ๋œ๋‹ค..!!!)

์ดํ›„ ๋ฐฉ๋ฒ•์€ ์œ„ ์˜์ƒ์„ ๋”ฐ๋ผํ•˜๋ฉด ๋œ๋‹ค ! 

 

์ด์ฒ˜๋Ÿผ extract widget ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ž˜ ๋”ฐ๋ผํ–ˆ๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค๊ฐ€ ํ•˜๋‚˜ ์ƒ์„ฑ๋์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค !

// ...
class BigCard extends StatelessWidget {
  const BigCard({
    Key? key,
    required this.pair,
  }) : super(key: key);

  final WordPair pair;

  @override
  Widget build(BuildContext context) {
    return Text(pair.asLowerCase);
  }
}
// ...

์ด์ œ ์ด refactoring์„ ํ†ตํ•ด ์•ฑ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

 

Add a Card

์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ๋ชฉํ‘œ๋ผ๊ณ  ํ–ˆ๋˜ ๊ทธ ํ™”๋ฉด์„ ๊ธฐ์–ต ํ•˜๋Š”๊ฐ€...?

์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ !!

์ด ์ด๋ฏธ์ง€๋ฅผ ๋ณด๋ฉด vastweb์ด ํŒŒ๋ž€์ƒ‰ ์นด๋“œ ์•ˆ์— ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ ์นด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ ๊ฒƒ์ด๋‹ค !

์•„๊นŒ ์‚ฌ์šฉํ–ˆ๋˜ refactor ๋ฉ”๋‰ด๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ธ๋ฐ, ์ด๋ฒˆ์—๋Š” extract ํ•˜์ง€ ์•Š๊ณ , Wrap with Padding์„ ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

 

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•๋ณด๋‹ค ๋‚ด๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ž ๊น ์–ธ๊ธ‰ํ•ด๋ณด๋ ค ํ•œ๋‹ค.

refactor ๋ฉ”๋‰ด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ vscode ์ขŒ์ธก์— ์žˆ๋Š” ์ „๊ตฌ ์•„์ด์ฝ˜์„ ๋ˆ„๋ฅด๋Š” ๊ฒƒ์ด๋‹ค.

 

์ด๋ ‡๊ฒŒ ์ „๊ตฌ ์•„์ด์ฝ˜ -> Wrap with Padding ์„ ์„ ํƒํ•˜๋ฉด, ์ž๋™์œผ๋กœ Padding์ด ์œ„์ ฏ์„ ๊ฐ์‹ธ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , Padding ํฌ๊ธฐ๋ฅผ 8.0 -> 20 ์œผ๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.

 

์ด์ œ, ์œ„์—์„œ ๋งŒ๋“  Padding ์œ„์ ฏ์„ Card ์œ„์ ฏ์œผ๋กœ ๊ฐ์‹ธ์ค„ ๊ฒƒ์ด๋‹ค. ์ฆ‰, Padding ์œ„์ ฏ์˜ ์ƒ์œ„ ์œ„์ ฏ์œผ๋กœ Card ์œ„์ ฏ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

padding ์˜†์— ์žˆ๋Š” ์ „๊ตฌ ์•„์ด์ฝ˜์„ ๋ˆŒ๋Ÿฌ์„œ (์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.) Wrap with widget...์„ ์„ ํƒํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๋งŒ๋“ค์–ด์ง„ widget ํ…์ŠคํŠธ๋ฅผ ์ง€์šฐ๊ณ , Card๋ฅผ ์ž…๋ ฅํ•œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๋นจ๊ฐ„ ์ค„๋„ ์‚ฌ๋ผ์งˆ ๊ฒƒ์ด๋‹ค !

 

์ค‘๊ฐ„์ ๊ฒ€์„ ํ•ด๋ณด์ž..!

์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ ์™”๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

Theme and style

์ด์ œ ์นด๋“œ ์ƒ‰์„ ๋ฐ”๊ฟ”์ค„ ๊ฑด๋ฐ, ์ผ๊ด€๋œ ์ƒ‰ ๊ตฌ์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ธฐ ๋•Œ๋ฌธ์—, ์•ฑ์˜ ํ…Œ๋งˆ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ‰์„ ์„ ํƒํ•  ๊ฒƒ์ด๋‹ค.

main.dart์—์„œ BigCard ํด๋ž˜์Šค๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

lib/main.dart

// ...

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);         // ← Add this.

    return Card(
      color: theme.colorScheme.primary,    // ← And also this.
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Text(pair.asLowerCase),
      ),
    );
  }

// ...

์ด๋ ‡๊ฒŒ ์œ„์—์„œ ์ถ”๊ฐ€ํ•œ ๋‘ ์ฝ”๋“œ๋Š” ๊ต‰์žฅํžˆ ๋งŽ์€ ์ผ์„ ํ•œ๋‹ค.

  • ๋จผ์ €, ์ฒซ๋ฒˆ์งธ ์ฝ”๋“œ๋Š” ์•ฑ์˜ ํ˜„์žฌ ํ…Œ๋งˆ๋ฅผ Theme.of(context)๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
  • ๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ๋Š” ํ…Œ๋งˆ์˜ colorScheme ์†์„ฑ๊ณผ ๋™์ผํ•˜๊ฒŒ ์นด๋“œ์˜ ์ƒ‰์ƒ์„ ์ •์˜ํ•œ๋‹ค. 
    • ์ƒ‰ ๊ตฌ์„ฑํ‘œ๋Š” ๋งŽ์€ ์ƒ‰์„ ํฌํ•จํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ ์ƒ‰์€ ์•ฑ์˜ primary color(์•ฑ์„ ์ •์˜ํ•˜๋Š”)์ด๋‹ค.

์ฆ‰, ์šฐ๋ฆฌ๋Š” ๋‘ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ MyApp ํด๋ž˜์Šค์—์„œ ์ •์˜ํ•œ theme color๋ฅผ ๋ถˆ๋Ÿฌ์˜จ ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ, ์œ„์˜ seedColor๋ฅผ ๋ฐ”๊พธ๋ฉด, ํ•ด๋‹น ์นด๋“œ์˜ ์ƒ‰๋„ ๊ฐ™์ด ๋ฐ”๋€Œ๊ฒŒ ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ theme color๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์•ฑ์˜ ์ „์ฒด์ ์ธ ๋ฉ”์ธ ์ƒ‰์„ ๋ฐ”๊ฟ”์•ผ ํ•  ๋•Œ, ๊ทธ ์ƒ‰์ด ์‚ฌ์šฉ๋œ ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ์ฐพ์ง€ ์•Š๊ณ , MyApp์˜ theme์—์„œ ์ƒ‰๋งŒ ๋ฐ”๊ฟ”์ฃผ๋ฉด, ๋ชจ๋‘ ๋ฐ”๋€Œ๊ฒŒ ๋œ๋‹ค.

 

TextTheme

์ง€๊ธˆ๊นŒ์ง€ ์™„์„ฑํ•œ ํ™”๋ฉด์„ ๋ณด๋ฉด ์ด๋Ÿฌํ•˜๋‹ค.

ํ•˜์ง€๋งŒ, ์นด๋“œ ์•ˆ์— ์žˆ๋Š” ๊ธ€์”จ๊ฐ€ ๊ฒ€์€์ƒ‰์ด๋ฉฐ, ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ์ž‘์•„ ์ฝ๊ธฐ ํž˜๋“ค๋‹ค.

์ด์ œ BigCard์˜ build() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ณ ์ณ์„œ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

 

๋‹ค์Œ๊ณผ ๊ฐ™์ด BigCard์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž

 

lib/main.dart

// ...

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    // ↓ Add this.
    var style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );

    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20),
        // ↓ Change this line.
        child: Text(pair.asLowerCase, style: style),
      ),
    );
  }

// ...
  • theme.textTheme์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ app์˜ font theme์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” bodyMedium(medium size์˜ ํ…์ŠคํŠธ๋ฅผ ์œ„ํ•œ), caption(์ด๋ฏธ์ง€๋ฅผ ์œ„ํ•œ), headlineLarge(large headlines๋ฅผ ์œ„ํ•œ)๊ณผ ๊ฐ™์€ ์†์„ฑ๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.
  • displayMedium property๋Š” ๊ณต์‹ ๋ฌธ์„œ์—, "์งง๊ณ  ์ค‘์š”ํ•œ ํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ" ๋ผ๊ณ  ๋‚˜์™€์žˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์™€ ๊ฐ™๋‹ค !
  • displayMedium ๋Š” ์ด๋ก ์ ์œผ๋กœ null์ด ๋  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ Dart๋Š” null-safe์ด๊ธฐ ๋•Œ๋ฌธ์— null์ด ๋˜๋„๋ก ๋‚ด๋ฒ„๋ ค๋‘์ง€ ์•Š๋Š”๋‹ค.. ๊ทธ๋ž˜์„œ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ! ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์šฐ๋ฆฌ๊ฐ€ ๋ญ˜ ํ•˜๊ณ  ์‹ถ์€์ง€ Dart๊ฐ€ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•œ ๊ฒƒ์€ ์ด ๊ฒฝ์šฐ์— ํ•ด๋‹นํ•˜์ง€ ์•Š๋Š”๋‹น..ใ…Žใ…Ž
  • displayMedium ์— copyWith() ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์šฐ๋ฆฌ๊ฐ€ ์ •์˜ํ•œ ์ˆ˜์ •์‚ฌํ•ญ๊ณผ ํ•จ๊ป˜ ํ…์ŠคํŠธ ์Šคํƒ€์ผ์˜ ๋ณต์‚ฌ๋ณธ์ด return ๋œ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ–ˆ๋˜ ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด, ์šฐ๋ฆฌ๋Š” ํ…์ŠคํŠธ ์ƒ‰์ƒ๋งŒ ๋ณ€๊ฒฝํ•œ ๊ฒƒ์ด๋‹ค.
  • ๋˜ ๋‹ค๋ฅธ ์ƒˆ๋กœ์šด ์ƒ‰์ƒ์„ ์–ป๊ณ  ์‹ถ๋‹ค๋ฉด, ์•ฑ์˜ ํ…Œ๋งˆ์— ๋‹ค์‹œ ์ ‘๊ทผํ•˜๋ฉด ๋œ๋‹ค. 

์ง€๊ธˆ๊นŒ์ง€ ํ•œ ๊ฒฐ๊ณผ์ด๋‹ค..!!

ํ›„... step 5... ์ƒ๊ฐ๋ณด๋‹ค ๊ธธ๋‹ค.....

ํ•˜์ง€๋งŒ...! ๋ฒŒ์จ 50%๋Š” ํ–ˆ์œผ๋‹ˆ.. ๊ดœ์ฐฎ๋‹ค....!!!!!!

๊ณ„์† ๊ฐ€๋ณด์ž๊ตฌ...

 

Improve accessibility

flutter๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์•ฑ์— ์—‘์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด์„œ, flutter ์•ฑ์€ ์•ฑ์˜ ๋ชจ๋“  ํ…์ŠคํŠธ๋“ค์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ‘œ์‹œํ•ด์„œ TalkBack ๋ฐ VoiceOver์™€ ๊ฐ™์€ ๊ฒƒ๋“ค์ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

pair.asLowerCase๋ณด๋‹ค๋Š” upper camel case๊ฐ€ screen reader๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋‹จ์–ด๋ฅผ ์ธ์‹ํ•˜๋Š” ๊ฒƒ์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

์ž์„ธํ•œ ๋ถ€๋ถ„์€ ์ฝ”๋“œ๋žฉ์„ ๋ณด์‹œ๊ธธ...... (์ ˆ๋Œ€ ๊ท€์ฐฎ์•„์„œ ์ƒ๋žตํ•˜๋Š”๊ฒŒ ๋งž์Šต๋‹ˆ๋‹ค..ใ…Žใ…Ž)

 

๊ทธ๋ž˜์„œ..! ๊ฒฐ๊ตญ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด๋ณด์ž.

๊ทธ๋Ÿฌ๋ฉด, ์ด์ œ screen readers๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ฐ ๋‹จ์–ด ์Œ๋“ค์„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. (๋ฌผ๋ก , UI์—๋Š” ๋ณ€ํ™”๊ฐ€ ์—†์„ ๊ฒƒ์ด๋‹ค!)

// ...

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    var style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );

    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20),

        // ↓ Make the following change.
        child: Text(
          pair.asLowerCase,
          style: style,
          semanticsLabel: pair.asPascalCase,
        ),
      ),
    );
  }

// ...

๋ณ€ํ™”๋ฅผ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, screen reader๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด์‹œ๊ธธ...!!

 

 

Center the UI

์ด์ œ..!! UI์˜ ์„ผํ„ฐ๋ฅผ ๋งž์ถฐ์„œ ์‹œ๊ฐ์ ์ธ ๋ถˆํŽธํ•จ์„ ํ•ด์†Œํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.

๋จผ์ €, BigCard ๋Š” Column์˜ ๋ถ€๋ถ„์ž„์„ ๊ธฐ์–ตํ•ด์•ผ ํ•œ๋‹ค. Column์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž์‹๋“ค์„ top์œผ๋กœ ํ•œ๋ฒˆ์— ๋‘์ง€๋ฉด, ์ด๋ฅผ ์‰ฝ๊ฒŒ override ํ•  ์ˆ˜ ์žˆ๋‹ค.

MyHomePage์˜ build() ๋ฉ”์†Œ๋“œ๋กœ ๊ฐ€์„œ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ”๊ฟ”๋ณด์ž..!

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,  // ← Add this.
        children: [
          Text('A random AWESOME idea:'),
          BigCard(pair: pair),
          ElevatedButton(
            onPressed: () {
              appState.getNext();
            },
            child: Text('Next'),
          ),
        ],
      ),
    );
  }
}

// ...

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, Column ์•ˆ์— ์žˆ๋Š” children๋“ค์ด main(vertical=์ˆ˜์ง) axis์— ๋งž์ถฐ center๊ฐ€ ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์‹ค Column ์•ˆ์— ์žˆ๋Š” children๋“ค์€ ์ด๋ฏธ main axis ๋ฐฉํ–ฅ์˜ center๊ฐ€ ๋งž์ถฐ์ ธ ์žˆ๋‹ค. ์ฆ‰, ๊ฐ€๋กœ ์„ผํ„ฐ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋Š”๋ฐ, ์ ์šฉ๋˜์ง€ ์•Š์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.

๊ทธ ์ด์œ ๋Š”, Column ์ž์ฒด๊ฐ€ ์„ผํ„ฐ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ, Column์˜ ์„ผํ„ฐ๋ฅผ ๋งž์ถฐ์ฃผ๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์„ผํ„ฐ ์œ„์น˜๋กœ ๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

Column์—์„œ ์ „๊ตฌ ์•„์ด์ฝ˜์„ ๋ˆ„๋ฅด๊ฑฐ๋‚˜, cmd . ๋˜๋Š” ctrl . ์„ ๋ˆŒ๋Ÿฌ Refactor menu๋ฅผ ์—ด์–ด์ค€๋‹ค.

Refactor menu -> Wrap with Center

๊ทธ ๊ฒฐ๊ณผ, ํ™”๋ฉด์˜ ์„ผํ„ฐ์— ์œ„์น˜ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค !!!

 

์ด์ œ ์กฐ๊ธˆ ๋””ํ…Œ์ผ์ ์ธ UI๋ฅผ ์ˆ˜์ •ํ•  ์ฐจ๋ก€์ด๋‹ค.

  • ์ผ๋‹จ, ์นด๋“œ ์œ„์— ์žˆ๋Š” "A random AWESOME idea:" ํ…์ŠคํŠธ๋Š” ์—†์• ๋„ ๋˜๋ฏ€๋กœ ์ง€์›Œ์ฃผ๊ฒ ๋‹ค.
  • ์นด๋“œ์™€ "Next" ๋ฒ„ํŠผ ์‚ฌ์ด์— ์—ฌ๋ฐฑ์ด ์žˆ์œผ๋ฉด ๋” ์ข‹์„ ๊ฒƒ ๊ฐ™์œผ๋ฏ€๋กœ, SizedBox ์œ„์ ฏ์„ ์‚ฌ์šฉํ•ด์„œ ๋‘ ์œ„์ ฏ ์‚ฌ์ด์— '๊ณต๊ฐ„'์„ ๋งŒ๋“ค์–ด์ค€๋‹ค

MyHomePage์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.

 

lib/main.dart

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            BigCard(pair: pair),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                appState.getNext();
              },
              child: Text('Next'),
            ),
          ],
        ),
      ),
    );
  }
}

// ...

์ด์ œ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ฒ˜์Œ์— ๋ชฉํ‘œํ•œ ์ด๋ฏธ์ง€์™€ ์ผ์น˜ํ•˜๋‹ค !!!!!

 

์ด๋ ‡๊ฒŒ.. ๊ธธ์—ˆ๋˜ step5๊ฐ€ ๋๋‚ฌ๋‹ค..!!!

๊ทธ์ € ๋ณด๊ณ  ๋งŒ๋“ค๊ธฐ๋งŒ ํ–ˆ๋‹ค๋ฉด, ๋นจ๋ฆฌ ๋๋‚ฌ์„ํ…Œ์ง€๋งŒ, ์ดํ•ดํ•˜๊ณ , ์ด๋ฅผ ์ •๋ฆฌํ•˜๋‹ค๋ณด๋‹ˆ ๊ต‰์žฅํžˆ ๊ธธ๊ฒŒ ๋Š๊ปด์กŒ๋‹ค...

 

๊ทธ๋งŒ ์ ๊ณ  ์‹ถ์€ ์ˆœ๊ฐ„๋„ ๋งŽ์ด ์žˆ์—ˆ์ง€๋งŒ...!!!!

 

๊ทธ๋ž˜๋„ step 5 ๋ !!

 

์•„์ฐธ! ํ˜น์‹œ ๋ชฐ๋ผ ํ•„์š”ํ•œ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ...!!

 

lib/main.dart

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyAppState(),
      child: MaterialApp(
        title: 'Namer App',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        ),
        home: MyHomePage(),
      ),
    );
  }
}

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();

  void getNext() {
    current = WordPair.random();
    notifyListeners();
  }
}

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            BigCard(pair: pair),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                appState.getNext();
              },
              child: Text('Next'),
            ),
          ],
        ),
      ),
    );
  }
}

class BigCard extends StatelessWidget {
  const BigCard({
    Key? key,
    required this.pair,
  }) : super(key: key);

  final WordPair pair;

  @override
  Widget build(BuildContext context) {
    var theme = Theme.of(context);
    var style = theme.textTheme.displayMedium!.copyWith(
      color: theme.colorScheme.onPrimary,
    );

    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20),

        // ↓ Make the following change.
        child: Text(
          pair.asLowerCase,
          style: style,
          semanticsLabel: pair.asPascalCase,
        ),
      ),
    );
  }
}

// ...
728x90
๋ฐ˜์‘ํ˜•
728x90
๋ฐ˜์‘ํ˜•

1. Introduction

ํ•™์Šตํ•  ๋‚ด์šฉ์€!

โœ…  flutter๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์˜ ๊ธฐ์ดˆ

โœ…  flutter์—์„œ layout ๋งŒ๋“ค๊ธฐ

โœ…  ์•ฑ ๋™์ž‘๊ณผ user interaction์˜ ์—ฐ๊ฒฐ (์ข‹์•„์š” ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋Š” ๊ฒƒ์ด ๊ทธ ์˜ˆ)

โœ…  flutter ์ฝ”๋“œ๋ฅผ ์ •๊ฐˆํ•˜๊ฒŒ ์งœ๋Š” ๊ฒƒ

โœ…  ๋ฐ˜์‘ํ˜• ์•ฑ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ (screen ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ๊ฒŒ ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Œ !)

โœ…  ์•ฑ์˜ ์ผ๊ด€๋œ ํ˜•ํƒœ์™€ ๋Š๋‚Œ์„ ์ฃผ๋„๋ก 

 

2. Set up your Flutter environment (flutter ํ™˜๊ฒฝ ์„ค์ •)

๐Ÿ“ Visual Studio Code ์‚ฌ์šฉ

codelab ๊ณต์‹ ๋ฌธ์„œ์—์„œ vscode๋ฅผ ๋‹ค์šด๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์—ฐ๊ฒฐํ•ด๋‘์—ˆ๋‹ค!

 

๊ณต์‹๋ฌธ์„œ ๋งํฌ โฌ‡๏ธ 

https://codelabs.developers.google.com/codelabs/flutter-codelab-first#1

 

Your first Flutter app  |  Google Codelabs

In this codelab, you’ll learn how to build a Flutter app that generates random, cool-sounding names.

codelabs.developers.google.com

 

๊ฐœ๋ฐœ ํƒ€๊นƒ ์„ค์ •ํ•˜๊ธฐ (๋‹ค์Œ ์ค‘ ์›ํ•˜๋Š” os๋ฅผ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.)

flutter์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์ด์ž ํŠน์ง•์ธ ๋ถ€๋ถ„์ด๋‹ค.

multi-platform toolkit์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ์ฝ”๋“œ๋กœ ์„œ๋กœ ๋‹ค๋ฅธ os๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

os๋Š” ์ฃผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ  ์‹ถ์€ os๋ฅผ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.

  • iOS
  • Android
  • Windows
  • macOS
  • Linux
  • web

์ด๋•Œ ์ง์ ‘ ๊ธฐ๊ธฐ๋ฅผ ์—ฐ๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•ด๋„ ๋˜๊ณ , simulator๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœํ•ด๋„ ๋œ๋‹ค.

(๋‚˜๋Š” ์•ฝ 80%๋ฅผ simulator๋กœ ๊ฐœ๋ฐœํ•œ๋‹ค!)

 

Flutter ์„ค์น˜ํ•˜๊ธฐ

Flutter SDK ์„ค์น˜๋Š” ๋‹ค์Œ ๊ณต์‹ ๋ฌธ์„œ์— ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…๋˜์–ด ์žˆ๋‹ค.

https://docs.flutter.dev/

 

Flutter documentation

Get started with Flutter. Widgets, examples, updates, and API docs to help you write your first Flutter app.

docs.flutter.dev

codelab์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ์˜ 3๊ฐ€์ง€๋งŒ ์žˆ์œผ๋ฉด ๋œ๋‹ค.

1. Flutter SDK

2. Visual Studio Code (Flutter plugin์ด ์„ค์น˜๋œ)

3. ๊ฐœ๋ฐœ ํƒ€๊นƒ์— ์š”๊ตฌ๋˜๋Š” software (์˜ˆ๋ฅผ ๋“ค์–ด, Visual Studio Code๋Š” Windows, Xcode๋Š” macOS)

 

(์ด ์™ธ์—, flutter SDK ์„ค์น˜๋‚˜ ํ™˜๊ฒฝ ์„ค์ •์— ์–ด๋ ค์›€์ด ์žˆ๋‹ค๋ฉด, codelab 2๋‹จ๊ณ„์—์„œ ๋ณด์—ฌ์ฃผ๋Š” StackOverflow๋ฅผ ์ฐธ๊ณ ํ•˜๊ธธ !)

 

3. Create a project

  • Visual Studio Code๋ฅผ ์‹คํ–‰ํ•˜๊ณ  command palette๋ฅผ Open. (  F1  ๋˜๋Š”  ctrl+Shift+P  ๋˜๋Š”  Shift+Cmd+P  )
  • "flutter new"๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ ๊ฒ€์ƒ‰๋œ Flutter: New Project ๋ฅผ ์„ ํƒํ•œ๋‹ค.
    • ๋งŒ์•ฝ flutter ํ™˜๊ฒฝ ์„ค์ •์ด ์ œ๋Œ€๋กœ ์ด๋ฃจ์–ด์กŒ๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž˜ ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Flutter: New Project ๋ฅผ ์„ ํƒํ•˜๊ณ  Appliction์„ ์„ ํƒํ•œ๋‹ค.
  • ๋‹ค์Œ์œผ๋กœ ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ ์ž ํ•˜๋Š” ์œ„์น˜์™€, ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์„ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
  • ๋งŒ์•ฝ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹ ๋ขฐ์™€ ๊ด€๋ จํ•œ ์ฐฝ์ด ๋œฌ๋‹ค๋ฉด Yes~~๋ฅผ ์„ ํƒ !

์ถœ์ฒ˜:&nbsp;https://codelabs.developers.google.com/codelabs/flutter-codelab-first#2

์—ฌ๊ธฐ๊นŒ์ง€ ํ–ˆ๋‹ค๋ฉด ์ด์ œ ๋ฐ”๋กœ Flutter ๊ฐœ๋ฐœ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค !!

 

codelab์„ ๋”ฐ๋ผํ•˜๊ธฐ ์œ„ํ•ด ์ฃ„์ธก ์ƒ๋‹จ์— ์žˆ๋Š” ์•„์ด์ฝ˜์„ ๋ˆ„๋ฅด๊ณ , pubspec.yaml ํŒŒ์ผ์„ ์„ ํƒํ•œ๋‹ค.

ํ•ด๋‹น ํด๋”์— ์žˆ๋Š” ๋‚ด์šฉ ์ค‘, ๊ฐ€์žฅ ์œ„ ๋‘ ์ค„์„ ์ œ์™ธํ•œ ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์ง€์šด ๋’ค, ์ด ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ๋ถ™์—ฌ๋„ฃ์–ด์ค€๋‹ค.

(name๊ณผ description๋ถ€๋ถ„์€ ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค !)

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 0.0.1+1

environment:
  sdk: '>=2.18.4 <3.0.0'

dependencies:
  flutter:
    sdk: flutter

  english_words: ^4.0.0
  provider: ^6.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true

์ด pubspec.yaml์€ ์•ฑ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ํŒŒ์ผ์ด๋‹ค. ์ด ์•ฑ์˜ ํ˜„์žฌ ๋ฒ„์ „, dependencies, assets ๋“ฑ์˜ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค.

 

  • ๋‹ค์Œ์€ ๊ฐ™์€ ์•„์ด์ฝ˜ ๋‚ด์— ์žˆ๋Š” analysis_options.yaml ํŒŒ์ผ์„ ๋ฐ”๊ฟ”์ค€๋‹ค.
    • ์•ˆ์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์ง€์šฐ๊ณ , ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ถ™์—ฌ๋„ฃ์–ด์ค€๋‹ค.
include: package:flutter_lints/flutter.yaml

linter:
  rules:
    prefer_const_constructors: false
    prefer_final_fields: false
    use_key_in_widget_constructors: false
    prefer_const_literals_to_create_immutables: false
    prefer_const_constructors_in_immutables: false
    avoid_print: false

์ด ํŒŒ์ผ์€ ์–ผ๋งˆ๋‚˜ ์—„๊ฒฉํ•˜๊ฒŒ ์šฐ๋ฆฌ๊ฐ€ ์ง  ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. ์ด ๋ถ€๋ถ„์€ ์–ธ์ œ๋“ ์ง€ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ˜„์žฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ฒ˜์Œ ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‰ฝ๊ฒŒ ๋„˜์–ด๊ฐ€์ค˜~ ํ•˜๊ณ  ์ด์•ผ๊ธฐํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

 

- ๋งˆ์ง€๋ง‰์œผ๋กœ main.dart ํŒŒ์ผ์„ ๋ฐ”๊ฟ”์ค€๋‹ค. (์œ„์น˜๋Š” lib/main.dart)

ํŒŒ์ผ์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์ง€์šฐ๊ณ , ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•œ๋‹ค.

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyAppState(),
      child: MaterialApp(
        title: 'Namer App',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        ),
        home: MyHomePage(),
      ),
    );
  }
}

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();

    return Scaffold(
      body: Column(
        children: [
          Text('A random idea:'),
          Text(appState.current.asLowerCase),
        ],
      ),
    );
  }
}

์ด์ œ ๋ชจ๋“  setting์ด ๋๋‚ฌ๋‹ค !!!!

์˜ค์˜ˆ !! ๐ŸŽ‰

 

๋ณธ๊ฒฉ์ ์œผ๋กœ ๋‹ค์–‘ํ•œ ์œ„์ ฏ๋“ค์„ ์‚ฌ์šฉํ•ด์„œ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์งœ๋ณด์ž !!

 

4. Add a button

์ด์ œ Next button์„ ๋งŒ๋“ค์–ด๋ณด์ž !

.

.

๊ทธ ์ „์— ์•ฑ์„ Launchํ•ด๋ด์•ผ ํ•œ๋‹ค. 

๋จผ์ €  lib/main.dart  ๋ฅผ ์—ด์–ด target device๊ฐ€ ์„ ํƒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณธ๋‹ค.

vscode์˜ ์šฐ์ธก ํ•˜๋‹จ์„ ๋ณด๋ฉด ํ˜„์žฌ ์ง€์ •๋œ target device๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐ”๊พธ๊ณ  ์‹ถ๋‹ค๋ฉด, ์ด๋ฅผ ํด๋ฆญํ•ด์„œ ๋ฐ”๊พธ๋ฉด ๋œ๋‹ค.

๋‚˜๋Š” ๊ธฐ์กด์— ์—ฐ๊ฒฐํ•ด๋‘” ๊ธฐ๊ธฐ๊ฐ€ ์žˆ์–ด ๋ฐ”๋กœ ๊ทธ ๊ธฐ๊ธฐ๋กœ ์„ค์ •์ด ๋˜์–ด์žˆ์—ˆ๋‹ค. ๋งฅ์ด๋ผ๋ฉด ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋ฅผ ์—ด์–ด ios ๊ธฐ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , android studio๋ฅผ ํ†ตํ•ด ์•ˆ๋“œ๋กœ์ด๋“œ ๊ธฐ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๊ธฐ๋ฅผ ์—ฐ๊ฒฐํ–ˆ๋‹ค๋ฉด ! ํ•œ ๋ฒˆ ์‹คํ–‰ํ•ด๋ณด์ž !!

 

์šฐ์ธก ์ƒ๋‹จ์— ์žˆ๋Š” ์‹คํ–‰๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค!

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋œจ๋ฉด ์•„์ฃผ์•„์ฃผ ์ž˜ ๋”ฐ๋ผ์˜จ ๊ฒƒ์ด๋‹ค !!!!

๋งŒ์•ฝ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พธ์—ˆ๋‹ค๋ฉด, Command+s ๋˜๋Š” Ctrl+s๋ฅผ ํ•˜๋ฉด ๋ฐ”๋กœ๋ฐ”๋กœ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ฝ”๋“œ๋žฉ์—์„œ ์ œ์‹œํ•œ Hot Reload์— ๋Œ€ํ•œ stack overflow๋ฅผ ์ฐธ๊ณ ํ•˜๊ธธ !

 

์ด์ œ ์ง„์งœ ์ง„์งœ ์ง„์งœ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด๋ณผ๊ฑฐ๋‹ค !!!

 

lib/main.dart

// ...

    return Scaffold(
      body: Column(
        children: [
          Text('A random AWESOME idea:'),
          Text(appState.current.asLowerCase),

          // ↓ Add this.
          ElevatedButton(
            onPressed: () {
              print('button pressed!');
            },
            child: Text('Next'),
          ),

        ],
      ),
    );

// ...

๋‹ค์Œ๊ณผ ๊ฐ™์ด scaffold ๋‚ด์— ์žˆ๋Š” Column์— ElevatedButton์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

์ด๋•Œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ฝ˜์†”์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ main.dart๊ฐ€ ์–ด๋–ป๊ฒŒ ์‹คํ–‰๋˜๋Š”์ง€๋ฅผ ์ดํ•ดํ•ด๋ณด์ž

lib/main.dart์˜ ๊ฐ€์žฅ ์ƒ๋‹จ์—์„œ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

// ...

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

// ...

์šฐ๋ฆฌ๋Š” main() ์ด๋ผ๋Š” ์ด๋ฆ„์˜ ํ•จ์ˆ˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ํ•จ์ˆ˜ ๋‚ด์— ์žˆ๋Š” ์ฝ”๋“œ๋Š” MyApp์— ์ •์˜๋œ ์•ฑ์„ ์‹คํ–‰ํ•˜๋„๋ก Flutter์— ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

 

MyApp ํด๋ž˜์Šค๋Š” StatelessWidget์„ ํ™•์žฅํ•œ๋‹ค. ์œ„์ ฏ์€ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ๋ชจ๋“  flutter app์˜ ์š”์†Œ๋“ค์ธ๋ฐ, ์•ฑ ๊ทธ ์ž์ฒด๋„ ์œ„์ ฏ์ด๋‹ค.

MyApp์— ์žˆ๋Š” ์ฝ”๋“œ๋Š” ์ „์ฒด ์•ฑ์„ ๊ตฌ์„ฑํ•œ๋‹ค. ์ด๋Š” app-wide state(๋‚˜์ค‘์— ๋‹ค๋ฃฐ ์˜ˆ์ •!) ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์•ฑ์˜ ์ด๋ฆ„์„ ์ง“๊ณ , ์‹œ๊ฐ์  theme์„ ์ •์˜ํ•˜๊ณ , "home" ์œ„์ ฏ(๊ทธ๋Ÿฌ๋‹ˆ๊นŒ, ์•ฑ์˜ ์‹œ์ž‘ ์ง€์ )์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

lib/main.dart

// ...

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();
}

// ...

flutter์—๋Š” app state๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋งŽ์€ ๋ฐฉ๋ฒ•๋“ค์ด ์žˆ๋‹ค. ๊ฐ€์žฅ ์‰ฝ๊ฒŒ ์ด์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š” ChangeNotifier์ด๋‹ค.

MyAppState๋Š” function์— ์•ฑ์ด ํ•„์š”๋กœ ํ•˜๋Š” data๋ฅผ ์ •์˜ํ•œ๋‹ค. 

  • state class๋Š” ๋ณ€ํ™”๋ฅผ ์•Œ๋ฆฌ๋Š” ChangeNotifier๋ฅผ ํ™•์žฅํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋งŒ์•ฝ ํ˜„์žฌ ๋‹จ์–ด๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค๋ฉด, ์•ฑ์— ์žˆ๋Š” ์–ด๋–ค ์œ„์ ฏ์ด ์ด๋ฅผ ์•Œ ํ•„์š”๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. 
  • MyApp์— ์‚ฌ์šฉํ–ˆ๋“ฏ์ด, ChangeNotifierProvider๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒํƒœ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์•ฑ์— ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” ์•ฑ์— ์žˆ๋Š” ์–ด๋–ค ์œ„์ ฏ์ด๋ผ๋„ ์ด ์ƒํƒœ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
  • ์ฆ‰, ์‰ฝ๊ฒŒ ์ด์•ผ๊ธฐํ•˜๋ฉด ChangeNotifier๋ฅผ MyAppState์— ์‚ฌ์šฉํ•˜๋ฉด, ์•ฑ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ณ€ํ™”๋“ค์„ ๋‹ค๋ฅธ ์œ„์ ฏ๋“ค์ด ์•Œ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
    • MyApp์ด ๊ฐ€์žฅ ์ƒ์œ„ ์œ„์ ฏ์ด๋ฉฐ, ChangeNotifier๋Š” ๋ณ€ํ™”๋ฅผ ์ธ์ง€ํ•˜๊ณ  ์ด๋ฅผ ์œ„์ ฏ์— ์•Œ๋ฆฌ๋Š” ์—ญํ• ์ž„์„ ์ดํ•ดํ•˜๋ฉด ๋” ์‰ฝ๋‹ค

๋งˆ์ง€๋ง‰์œผ๋กœ MyHomePage์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

์ด ์œ„์ ฏ์€ ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์ˆ˜์ •ํ•œ ์œ„์ ฏ์ด๋‹ค. ๊ณต์‹๋ฌธ์„œ์—์„œ ์„ค๋ช…ํ•œ ๋‚ด์šฉ์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์™€์„œ ์กฐ๊ธˆ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•  ๊ฒƒ์ด๋‹ค.

// ...

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {           // ← 1
    var appState = context.watch<MyAppState>();  // ← 2

    return Scaffold(   // ← 3
      body: Column(    // ← 4
        children: [
          Text('A random AWESOME idea:'),        // ← 5
          Text(appState.current.asLowerCase),    // ← 6
          ElevatedButton(
            onPressed: () {
              print('button pressed!');
            },
            child: Text('Next'),
          ),
        ],      // ← 7
      ),
    );
  }
}

// ...
  1. ๋ชจ๋“  ์œ„์ ฏ์€ ์œ„์ ฏ์˜ ํ™˜๊ฒฝ์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋˜์–ด ์œ„์ ฏ์ด ํ•ญ์ƒ ์ตœ์‹  ์ƒํƒœ๋ฅผ ๊ฐ–๋„๋ก ํ•˜๋Š” build() method๋ฅผ ์ •์˜ํ•œ๋‹ค.
  2. watch method๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ์˜ ๋ณ€ํ™”๋ฅผ ์ถ”์ ํ•˜๊ณ , ์•ฑ์˜ ํ˜„ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
  3. ๋ชจ๋“  build ๋ฉ”์„œ๋“œ๋Š” ์œ„์ ฏ ๋˜๋Š” ์ค‘์ฒฉ๋œ ์œ„์ ฏ ํŠธ๋ฆฌ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ๊ฒฝ์šฐ ์ตœ์ƒ์œ„ ์œ„์ ฏ์€ Scaffold์ด๋‹ค. Scaffold๋Š” ์‹ค์ œ๋กœ ๊ต‰์žฅํžˆ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋ฉฐ, main.dart์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋œ๋‹ค.  return Scaffold(); 
  4. Column์€ ์•„์ฃผ ์ž์ฃผ ์“ฐ์ด๋ฉด์„œ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ layout widget์ด๋‹ค. ์ด ์œ„์ ฏ์€ ๋งŽ์€ ์ˆ˜์˜ children์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์œ„์—์„œ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ ๋ฐฐ์น˜ํ•œ๋‹ค. default๋กœ column์€ ์ขŒ์ธก ์ƒ๋‹จ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š”๋ฐ, ์ด๋ฅผ center๋กœ ๋ฐ”๊ฟ”์ค„ ์ˆ˜ ์žˆ๋‹ค. (๋’ค์—์„œ ๋‹ค๋ฃฐ ์˜ˆ์ •)
  5. Text("")์˜ ํ˜•ํƒœ๋กœ ์“ฐ์ด๋ฉฐ, "" ์•ˆ์— ์›ํ•˜๋Š” ๋ฌธ์ž์—ด์„ ๋„ฃ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ํ™”๋ฉด์— ๊ทธ๋ ค์ง„๋‹ค.
  6. ์ด Text ์œ„์ ฏ์€ appState๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ด ํด๋ž˜์Šค์˜ member์—๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. (์—ฌ๊ธฐ์—์„œ๋Š” current). 
    WordPair์€ asPascalCase, asLowerCase ๋˜๋Š” asSnakeCase์™€ ๊ฐ™์ด ์œ ์šฉํ•œ getter๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  7. flutter์—๋Š” ๊ด„ํ˜ธ๊ฐ€ ๊ต‰์žฅํžˆ ๋งŽ์ด ์“ฐ์ด๋Š”๋ฐ, ์‰ผํ‘œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ํ•˜์ง€๋งŒ, vscode์—์„œ๋Š” ์‰ผํ‘œ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ๋ถ„ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์ž๋™์ •๋ ฌ์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์„ ํƒ์— ๋”ฐ๋ผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ๋‚˜๋Š” ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ๋ฐ, ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๋Š”๊ฒŒ ์‹ซ์€ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ๊ตฌ๋ถ„์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด๋‹ค.

 

์ง์ ‘ ํ•ด๋ณด์ž

MyAppState๋กœ ๊ฐ€์„œ getNext method๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์ž.

lib/main.dart

// ...

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();

  // ↓ Add this.
  void getNext() {
    current = WordPair.random();
    notifyListeners();
  }
}

// ...

getNext() ๋ฉ”์†Œ๋“œ๋Š” current์— ์ƒˆ๋กœ์šด ๋žœ๋ค WordPair๋ฅผ ์žฌํ• ๋‹นํ•ด์ค€๋‹ค. ๋˜ํ•œ ์ด๋ฅผ notifyListeners()๋ผ ๋ถ€๋ฅด๋Š”๋ฐ, (ChangeNotifier์˜ ๋ฉ”์†Œ๋“œ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.)์ด๋Š” MyAppState๋ฅผ ๋ณด๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ์„ ์ค€๋‹ค.

 

 

 

lib/main.dart

// ...

    ElevatedButton(
      onPressed: () {
        appState.getNext();  // ← This instead of print().
      },
      child: Text('Next'),
    ),

// ...

์ด์ œ Next ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ๋‹จ์–ด๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค !!!

 

์ƒ๊ฐ๋ณด๋‹ค ๋„ˆ๋ฌด ๊ธธ์–ด์ ธ์„œ ๋‹ค์Œ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ ๊ธ€์— ์ ์–ด์•ผ๊ฒ ๋‹ค !!

 

ํ•„์š”ํ•œ ์‚ฌ๋žŒ์ด ์žˆ์„์ง€ ๋ชฐ๋ผ codelab์˜ step1~step4๊นŒ์ง€์˜ lib/main.dart ์ „์ฒด ์ฝ”๋“œ์ด๋‹ค.

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyAppState(),
      child: MaterialApp(
        title: 'Namer App',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        ),
        home: MyHomePage(),
      ),
    );
  }
}

class MyAppState extends ChangeNotifier {
  var current = WordPair.random();

  void getNext() {
    current = WordPair.random();
    notifyListeners();
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();

    return Scaffold(
      body: Column(
        children: [
          Text('A random idea:'),
          Text(appState.current.asLowerCase),
          ElevatedButton(
            onPressed: () {
              appState.getNext(); // ← This instead of print().
            },
            child: Text('Next'),
          ),
        ],
      ),
    );
  }
}
728x90
๋ฐ˜์‘ํ˜•
728x90
๋ฐ˜์‘ํ˜•
๋ฐ˜์‘ํ˜•
728x90
๋ฐ˜์‘ํ˜•
๋ฐ˜์‘ํ˜•

 

์™ธ์ฃผ๋ฅผ ํ•˜๋‹ค ๋ณด๋‹ˆ ๋ฌด์„  ๋””๋ฒ„๊น…์„ ํ•ด์•ผํ•  ์ผ์ด ์ž์ฃผ ์žˆ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ios 14์ธ๊ฐ€ 15๋ถ€ํ„ฐ๋Š” '$ flutter run'์œผ๋กœ๋Š” ๋ฌด์„ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.

 

 

flutter run -d ๊ธฐ๊ธฐ๋ฒˆํ˜ธ --release

 

๊ธฐ๊ธฐ๋ฒˆํ˜ธ ์ž๋ฆฌ์— ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ธฐ๊ธฐ์˜ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ํœด๋Œ€ํฐ์— ์•ฑ์ด ์„ค์น˜๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ช‡ ๊ฐ€์ง€ ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค๋ฉด, xcode์—์„œ ๊ธฐ๊ธฐ๋ฅผ ์„ ํƒํ•˜๊ณ  ๋นŒ๋“œํ•œ ๋’ค ๋‹ค์‹œ ์‹œ๋„ํ•˜๋ฉด ๋œ๋‹ค.

 

์•ฑ์ด ์„ค์น˜๋˜๊ณ  ๋‚˜์„œ๋Š” ์„ ์„ ์ œ๊ฑฐํ•˜๊ณ ๋„ ๋ฌด์„ ์œผ๋กœ ์•ฑ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

728x90
๋ฐ˜์‘ํ˜•
๋ฐ˜์‘ํ˜•

 

728x90
๋ฐ˜์‘ํ˜•

 

728x90
๋ฐ˜์‘ํ˜•
728x90
๋ฐ˜์‘ํ˜•
728x90
๋ฐ˜์‘ํ˜•

flutter๋กœ ์•ฑ์„ ์—ด์‹ฌํžˆ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋‹ˆ iphone์— ์ง์ ‘ ์‹คํ–‰์‹œ์ผœ์„œ ๊ฐœ๋ฐœ ๊ณผ์ •์„ ํ™•์ธํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

์‹ค์ œ ์•ฑ์—์„œ๋Š” padding์ด๋‚˜, ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๋“ฑ์ด ์–ด์ƒ‰ํ•˜๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— iphone ์—ฐ๋™์ด ์‹œ๊ธ‰ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ flutter ์ดˆ๋ณด์ธ ๋‚ด๊ฒŒ xcode๋ฅผ ๋‹ค๋ฃจ๋Š” ์ผ์€ ๋„ˆ๋ฌด ์–ด๋ ค์› ๋‹ค๐Ÿ˜ญ

์—ฌ๋Ÿฌ reference๋“ค์„ ์ฐธ๊ณ ํ–ˆ๋Š”๋ฐ, ์˜คํžˆ๋ ค ๊ทธ๊ฒƒ์ด ๋‚ด๊ฒŒ๋Š” ๋…์ด ๋˜์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์‹คํŒจ ๋์— ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๊ธฐ๋ฅผ ๋ฐ˜๋ณตํ–ˆ๋‹ค.

๋‹ค์‹œ๋Š” ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜์”ฉ ์ •๋ฆฌํ•˜๋ฉฐ ๊ธฐ๋กํ•˜๋ ค ํ•œ๋‹ค.

 

 

1. iphone์„ ๋งฅ์— ์—ฐ๊ฒฐํ•œ๋‹ค.

๋งฅ์— ์—ฐ๊ฒฐํ•˜๋ฉด, finder์—์„œ ์—ฐ๊ฒฐ๋œ iphone์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•ด๋‹น ๊ธฐ๊ธฐ๋ฅผ ์„ ํƒํ•˜๋ฉด, ์‹ ๋ขฐ์— ๋Œ€ํ•œ ๋ถ€๋ถ„์ด ๋‚˜์˜ค๋Š”๋ฐ ์‹ ๋ขฐ๋ฅผ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค. 

 

 

 

 

2. ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ํด๋”๋ฅผ ์ฐพ๋Š”๋‹ค.

๋‚˜๊ฐ™์€ ๊ฒฝ์šฐ, ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ํด๋” ๋ช…์ด "my_work_plz" ์˜€๋‹ค. (ํด๋”๋ช…์—์„œ๋„ ๊ฐ„์ ˆํ•จ์„...)

ํ•ด๋‹น ํด๋”์— ๋“ค์–ด๊ฐ€์„œ ios > Runner.xcworkspace ๋กœ ์ด๋™ํ•ด์„œ ํŒŒ์ผ์„ ์—ฐ๋‹ค. ํŒŒ์ผ์„ ์—ด๊ณ  ์ƒ๋‹จ์— ์žˆ๋Š” Runner > ๊น€ํ•˜๋žŒ์˜ iphone์ด ๋˜๋„๋ก ํ•œ๋‹ค.

Runner > ์ด ๋ถ€๋ถ„์— ios Device๊ฐ€ ์„ ํƒ๋˜๋ฉด ๋œ๋‹ค.

 

 

 

 

 

3. Runner > Targets์— Runner๋ฅผ ์„ ํƒํ•˜๊ณ , Signing & Capabilities์˜ Signing

์—ฌ๊ธฐ์—์„œ add account๋ฅผ ์„ ํƒํ•ด์„œ apple id๋กœ ๋กœ๊ทธ์ธ์„ ํ•œ๋‹ค. 

* ์ „์ œ์กฐ๊ฑด์€, apple developer.com ์—์„œ ๊ฐœ๋ฐœ์ž ๋“ฑ๋ก์„ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ!

 

Bundle Identifier๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๋งŒํ•œ ๊ฒƒ์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š”,

com.example.firstwork -> com.example.firstworksesd ๋กœ ๋ฐ”๊ฟ”์คฌ๋‹ค. 

 

 

 

 

4. ์ด๋ ‡๊ฒŒ Bundle Identifier ๊ฐ€ ํ†ต๊ณผ๋˜๋ฉด, ์ด ์‹คํ–‰ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ๋ฉด ๋œ๋‹ค.

 

 

 

 

5. keychain password

์ด๋ ‡๊ฒŒ ์‹คํ–‰์„ ํ•˜๋‹ค ๋ณด๋ฉด, keychain password๋ฅผ ์ž…๋ ฅํ•˜๋ผ๋Š” ์ฐฝ์ด ๋‚˜์˜ค๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์€ ๋ฏธ์ฒ˜ ์บก์ณํ•˜์ง€ ๋ชปํ–ˆ๋‹ค..๐Ÿ˜ญ

์‚ฌ์‹ค ๋‚˜๋Š” keychain password์—์„œ๋„ ๊ฝค๋‚˜ ๋งŽ์€ ์‹œ๊ฐ„์„ ์Ÿ์•˜๋‹ค.. keychain์ด ๋ญ”์ง€๋„ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋Š”๋ฐ, ๊ฐ‘์ž๊ธฐ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋ผ๊ณ  ํ•˜๋‹ˆ ๋งค์šฐ ๋‹นํ™ฉ์Šค๋Ÿฌ์› ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•œ ์ ์ด ์—†์–ด ๊ต‰์žฅํžˆ ๋‹นํ™ฉํ–ˆ์œผ๋‚˜, ๋Œ€๋ถ€๋ถ„ ์ปดํ“จํ„ฐ ์ž ๊ธˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ผ๊ณ  ํ•œ๋‹ค. 

๋ฌผ๋ก  ๋‚˜๋Š” ๋˜์ง€ ์•Š์•„์„œ, keychain password๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , ์žฌ์„ค์ •ํ–ˆ๋‹ค. ๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด ์ด ๋ถ€๋ถ„๋„ ํฌ์ŠคํŒ… ํ•ด๋ด์•ผ๊ฒ ๋‹ค.

Always Allow๋ฅผ ์„ ํƒํ•˜๋ฉด ๋‚˜์ค‘์— ํ›จ์”ฌ ํŽธํ•˜๋‹ค!

 

๊ทธ๋ ‡๊ฒŒ ์‹คํ–‰์„ ํ•˜๋‹ค ๋ณด๋ฉด, Could not launch "Runner" ๋ผ๋Š” ๋‹ค์ด์–ผ๋กœ๊ทธ๊ฐ€ ๋œฌ๋‹ค. ์ด๋Š” ์—ฐ๊ฒฐํ•˜๋ ค๋Š” ๊ธฐ๊ธฐ๊ฐ€ ๋‹น์‹ ์„ ๊ฐœ๋ฐœ์ž๋กœ ์‹ ๋ขฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ผ๋‹จ OK๋ฅผ ์„ ํƒํ•˜๊ณ , ์—ฐ๊ฒฐํ•˜๋ ค๋Š” ๊ธฐ๊ธฐ๋กœ ๊ฐ€๋ณด์ž.

 

 

 

 

 

6. ๊ธฐ๊ธฐ์—์„œ ์„ค์ • > ์ผ๋ฐ˜ > VPN ๋ฐ ๊ธฐ๊ธฐ ๊ด€๋ฆฌ

๊ธฐ๊ธฐ์—์„œ ์„ค์ • > ์ผ๋ฐ˜ > VPN ๋ฐ ๊ธฐ๊ธฐ ๊ด€๋ฆฌ๋กœ ์ด๋™ํ•ด์„œ Apple Development~~ ๋ถ€๋ถ„์„ ์„ ํƒํ•˜๊ณ , ์‹ ๋ขฐํ•˜๊ฒ ๋‹ค๋Š” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋œ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€๋งŒ ํ–ˆ๋‹ค๋ฉด ๋ฒŒ์จ 80%์ด์ƒ ๋๋‚ฌ๋‹ค!!

์ด๋ ‡๊ฒŒ ๊ธฐ๊ธฐ์—์„œ ์‹ ๋ขฐํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ๊นŒ์ง€ ์„ ํƒํ•œ ๋’ค, ๋‹ค์‹œ xcode์—์„œ ์‹คํ–‰ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด....!!

๊ธฐ๊ธฐ์—์„œ ๋˜ ์–ด๋–ค ์ฐฝ์ด ๋‚˜์˜จ๋‹ค. ์ด ๋ชจ๋“  ๋ถ€๋ถ„์„ ์บก์ณ ํ–ˆ์–ด์•ผ ํ–ˆ๋Š”๋ฐ.. ๋„ˆ๋ฌด ์•„์‰ฝ๋‹ค..๐Ÿ˜ข

์–ด์จŒ๋“ , xcode๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ๊ธฐ๊ธฐ์—์„œ ์–ด๋–ค ์ฐฝ์ด ๋‚˜์˜จ๋‹ค๋ฉด OK ๋˜๋Š” ํ™•์ธ์„ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.

์•„๋งˆ ๋กœ์ปฌ ๋„คํŠธ์›Œํฌ์— ๊ธฐ๊ธฐ๋ฅผ ์—ฐ๊ฒฐํ•  ๊ฒƒ์ด๋Š๋ƒ์— ๋Œ€ํ•œ ์ฐฝ์ด ๋‚˜์˜ฌ ๊ฒƒ์ด๋‹ค.

 

 

 

 

 

7. vscode ๋นŒ๋“œ

์ด์ œ xcode๋ฅผ ์ž ์‹œ ๋’ค๋กœ ๋‘๊ณ , ๋‹ค์‹œ vscode๋กœ ๋„˜์–ด์™€๋ณด์ž.

vscode์—์„œ ๋นŒ๋“œ๋ฅผ ํ•˜๊ธฐ ์ „์—, vscode ์šฐ์ธก ํ•˜๋‹จ์— ์›ํ•˜๋Š” ๊ธฐ๊ธฐ๊ฐ€ ์ž˜ ์—ฐ๊ฒฐ ๋๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

ํ™•์ธ์ด ๋๋‹ค๋ฉด, vscode์—์„œ ๋นŒ๋“œ๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด, ์—ฐ๊ฒฐํ•œ ๊ธฐ๊ธฐ์—์„œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๋ฉด ์ข‹๊ฒ ์ง€๋งŒ, ์•„์‰ฝ๊ฒŒ๋„ vscode์—์„œ ๋˜ ํ•˜๋‚˜์˜ ์ฐฝ์ด ๋œฐ ๊ฒƒ์ด๋‹ค...

๋งˆ์ง€๋ง‰ ์ฐฝ์ด๋‹ค.. ์ด ๋ถ€๋ถ„๋„ ์บก์ณ๋ฅผ ํ•˜์ง€ ๋ชปํ–ˆ๋Š”๋ฐ, "iproxy"์— ๋Œ€ํ•œ ๋ถ€๋ถ„์ด์—ˆ๋‹ค. vscode๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์ค‘์— "iproxy"๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ฐฝ์ด ๋œฌ๋‹ค๋ฉด, ์ผ๋‹จ cancel์„ ๋ˆ„๋ฅด์ž.

 

 

 

 

 

8. iproxy ํ•ด๊ฒฐํ•˜๊ธฐ

์ปดํ“จํ„ฐ์—์„œ flutter๋ฅผ ์ฐพ๋Š”๋‹ค. flutter ํด๋”๋ฅผ ์ฐพ์œผ๋ฉด, flutter > bin > cache ๋กœ ์ด๋™ํ•œ๋‹ค.

cache์— ์˜ค๋ฉด, "artifacts"๋ผ๋Š” ํด๋”๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

์ด artifacts๋ฅผ ์‚ญ์ œํ•˜๋ฉด ๋œ๋‹ค.

 

 

 

 

 

9. ๋‹ค์‹œ ๋นŒ๋“œ

๋‹ค์‹œ vscode๋กœ ๋Œ์•„์™€์„œ ๋นŒ๋“œํ•˜๋ฉด, ํŒŒ์ผ๋“ค์ด ๋‹ค์šด๋กœ๋“œ๋˜๊ณ , ๊ธฐ๊ธฐ์—์„œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค !!

 

728x90
๋ฐ˜์‘ํ˜•

'๐Ÿ’ง flutter' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[flutter] ์ƒˆ๋กญ๊ฒŒ ๋ฐ”๋€ codelab (step1-step4)  (0) 2023.02.07
์•„์ดํฐ ๋ฌด์„  ๋””๋ฒ„๊น…  (0) 2022.10.30
flutter album ์ ‘๊ทผ  (0) 2022.07.08
[Flutter] no device  (0) 2022.07.08
Padding class  (0) 2022.07.06

+ Recent posts