본문 바로가기
Programming/Flutter

[Flutter] 회사명 랜덤 생성기 제작 튜토리얼 Part 2

by 혀코 2022. 7. 24.

 

안녕하세요. 혀코입니다.

이번 시간에는 저번 시간에 진행했던 Flutter로 회사명 랜덤 생성기 제작 튜토리얼 Part 1에 이어서 Part 2를 진행해 보겠습니다. 아직 튜토리얼 Part 1을 진행하지 않으셨다면, 아래 링크를 통해서 Part 1 진행 하시고 이어서 진행 부탁 드립니다.

그럼 Part 2를 진행해 보겠습니다.

State Class를 다음과 같이 업데이트 합니다.

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>[]; /*1*/
  final _biggerFont = const TextStyle(fontSize: 18);
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: (context, i) {
          if (i.isOdd) return const Divider();

          final index = i ~/ 2;
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }
		  
          final alreadySaved = _saved.contains(_suggestions[index]); /*2*/
          return ListTile(
            title: Text(
              _suggestions[index].asPascalCase,
              style: _biggerFont,
            ),
            trailing: Icon(  /*3*/
              // 이미 저장되었다면, 채워진 하트를 표시하고 저장이 안되었다면, 비어있는 하트를 표시합니다.
              alreadySaved ? Icons.favorite : Icons.favorite_border, 
              // 이미 저장되었다면, 색상은 빨간색으로 해주고, 아니면, null 로 지정해줍니다.
              color: alreadySaved ? Colors.red : null, 
              // 레이블을 추가합니다. 저장된 상태라면, 아이콘을 누르게 될 경우 제거 그 반대의 경우 저장이 출력됩니다.
              semanticLabel: alreadySaved ? 'Remove from saved' : 'Save', 
            ),  /*3*/
          );
        });
  }
}

 

1. 좋아요 아이콘을 탭하면, 랜덤으로 생성된 회사명을 저장할 빈 배열을 _suggestions 변수에 생성합니다.

2. 이미 좋아요 아이콘을 눌러 저장된 회사명이 리스트에 있는지 확인합니다.

3. 해당 회사명이 저장이 됬는지 여부를 판단해서 좋아요 아이콘의 속성을 설정해줍니다.

이렇게 업데이트 하고 탭을 해도 아무런 변화가 없습니다.

onTap 속성을 아래와 같이 추가해 줍니다.

 

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>[];
  final _biggerFont = const TextStyle(fontSize: 18);
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: (context, i) {
          if (i.isOdd) return const Divider();

          final index = i ~/ 2; 
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }

          final alreadySaved = _saved.contains(_suggestions[index]);
          return ListTile(
            title: Text(
              _suggestions[index].asPascalCase,
              style: _biggerFont,
            ),
            trailing: Icon(
              alreadySaved ? Icons.favorite : Icons.favorite_border,
              color: alreadySaved ? Colors.red : null,
              semanticLabel: alreadySaved ? 'Remove from saved' : 'Save',
            ),
            onTap: () { /*1*/
              setState(() { // State를 변경합니다.
                if (alreadySaved) { // 이미 저장된 회사명인데 탭을 했을 경우,
                  _saved.remove(_suggestions[index]); // 삭제하고
                } else { // 저장된 회사명이 아닌 경우,
                  _saved.add(_suggestions[index]); // 저장합니다.
                }
              });
            },
          );
        });
  }
}

 

1. onTap 속성을 추가해서 setState를 통해 state를 변경해서 동작되게 합니다.

좋아요 아이콘을 탭하면 빨간 하트로 변경되는 것을 확인할 수 이습니다.

 

그 다음으로는 MyApp의 Scaffold를 삭제하고 다음과 같이 업데이트 합니다. 

 

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
    );
  }
}

 

_RandomWordsState class를 다음과 같이 업데이트 합니다.

AppBar에 메뉴 아이콘을 만들고, 메뉴 아이콘을 탭하면 두번째 스크린으로 넘어가서 저장된 회사명을 확인할 수 있게 구현합니다.

 

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>[];
  final _biggerFont = const TextStyle(fontSize: 18);

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (context) {
          final tiles = _saved.map(
            (pair) {
              return ListTile(
                title: Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );
          final divided = tiles.isNotEmpty
              ? ListTile.divideTiles(
                  context: context,
                  tiles: tiles,
                ).toList()
              : <Widget>[];

          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Startup Name Generator'),
        actions: [
          IconButton(
            icon: const Icon(Icons.list),
            onPressed: _pushSaved,
            tooltip: 'Saved Suggestions',
          )
        ],
      ),
      body: ListView.builder(
          padding: const EdgeInsets.all(16.0),
          itemBuilder: (context, i) {
            if (i.isOdd) return const Divider();

            final index = i ~/ 2;
            if (index >= _suggestions.length) {
              _suggestions.addAll(generateWordPairs().take(10));
            }

            final alreadySaved = _saved.contains(_suggestions[index]);
            return ListTile(
              title: Text(
                _suggestions[index].asPascalCase,
                style: _biggerFont,
              ),
              trailing: Icon(
                alreadySaved ? Icons.favorite : Icons.favorite_border,
                color: alreadySaved ? Colors.red : null,
                semanticLabel: alreadySaved ? 'Remove from saved' : 'Save',
              ),
              onTap: () {
                setState(() {
                  if (alreadySaved) {
                    _saved.remove(_suggestions[index]);
                  } else {
                    _saved.add(_suggestions[index]);
                  }
                });
              },
            );
          }),
    );
  }
}

 

이제 AppBar에 메뉴 아이콘이 나타나고, 메뉴 아이콘을 탭하면, 두번째 스크린으로 넘어가서 저장된 회사명을 확인할 수 있습니다.

 

 

 

이제 AppBar의 파란색 테마 스타일을 바꿔보겠습니다.

 

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(  /*1*/
      title: 'Startup Name Generator',
      theme: ThemeData( /*2*/
        appBarTheme: const AppBarTheme(
          backgroundColor: Colors.white,
          foregroundColor: Colors.black,
        ),
      ), /*2*/
      home: const RandomWords(), /*3*/
    );
  }
}

 

1. AppBar의 파란색 테마 스타일을 변경하기 위해서, const를 없애 줍니다.

2. AppBar의 테마의 스타일을 하얀색 배경에 검은색 텍스트로 변경해 줍니다.

3. const를 붙여줍니다.

 

전체 소스코드는 이렇게 작성되었습니다.

 

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      theme: ThemeData(
        appBarTheme: const AppBarTheme(
          backgroundColor: Colors.white,
          foregroundColor: Colors.black,
        ),
      ),
      home: const RandomWords(),
    );
  }
}

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

  @override
  State<RandomWords> createState() => _RandomWordsState();
}

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>[];
  final _biggerFont = const TextStyle(fontSize: 18);

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (context) {
          final tiles = _saved.map(
            (pair) {
              return ListTile(
                title: Text(
                  pair.asPascalCase,
                  style: _biggerFont,
                ),
              );
            },
          );
          final divided = tiles.isNotEmpty
              ? ListTile.divideTiles(
                  context: context,
                  tiles: tiles,
                ).toList()
              : <Widget>[];

          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Startup Name Generator'),
        actions: [
          IconButton(
            icon: const Icon(Icons.list),
            onPressed: _pushSaved,
            tooltip: 'Saved Suggestions',
          )
        ],
      ),
      body: ListView.builder(
          padding: const EdgeInsets.all(16.0),
          itemBuilder: /*1*/ (context, i) {
            if (i.isOdd) return const Divider(); /*2*/

            final index = i ~/ 2; /*3*/
            if (index >= _suggestions.length) {
              _suggestions.addAll(generateWordPairs().take(10)); /*4*/
            }

            final alreadySaved = _saved.contains(_suggestions[index]);
            return ListTile(
              title: Text(
                _suggestions[index].asPascalCase,
                style: _biggerFont,
              ),
              trailing: Icon(
                alreadySaved ? Icons.favorite : Icons.favorite_border,
                color: alreadySaved ? Colors.red : null,
                semanticLabel: alreadySaved ? 'Remove from saved' : 'Save',
              ),
              onTap: () {
                setState(() {
                  if (alreadySaved) {
                    _saved.remove(_suggestions[index]);
                  } else {
                    _saved.add(_suggestions[index]);
                  }
                });
              },
            );
          }),
    );
  }
}

 

이렇게 회사명 랜덤 생성기 제작 튜토리얼 Part2를 진행했습니다.

해당 정보가 유용하셨다면, 공감과 구독 부탁 드립니다.

감사합니다. :)

댓글