ram2 ๐Ÿš—

[flutter] ์ƒˆ๋กญ๊ฒŒ ๋ฐ”๋€ codelab (step6) ๋ณธ๋ฌธ

๐Ÿ’ง flutter

[flutter] ์ƒˆ๋กญ๊ฒŒ ๋ฐ”๋€ codelab (step6)

coram22 2023. 2. 9. 20:52
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
๋ฐ˜์‘ํ˜•