본문 바로가기
공허의 유산/사상의 도구

[Flutter]. 09. Flutter tutorial on codelab(5)

by 바른생활머시마 2023. 1. 24.
728x90
반응형

앞에서 화면을 꾸미는 내용을 좀 다뤄봤습니다.

https://learn-and-give.tistory.com/47

 

[Flutter]. 07. Flutter tutorial on codelab(4)

앞에서 UI를 재정의 하는 코드를 삽입하는 방법과 Refactoring 명령으로 Wrapping 하는 방법 등을 살펴보았습니다. https://learn-and-give.tistory.com/46 [Flutter]. 06. Flutter tutorial on codelab(3) 앞에서 앱의 가장 기

learn-and-give.tistory.com

이번에는 추천 된 wordpair를 기억 할 수 있도록, 마음에 드는 단어쌍에 Like라는 표시를 하는 기능입니다.

 

우선 화면 기획서는 아래와 같다고 하겠습니다.

 기능 구현은 일단 놔두고, 화면 구성 관점에서 살펴보면 Next 버튼 옆에 다른 버튼이 하나 추가되어야 하겠네요.

 같은 행에 여러 개의 Widget을 배열 할 수 있어야 되겠네요. Column위젯이 있었으니, Row위젯이 있을 것 같고....

 

State 관련 코드 추가

tutorial에서는 비지니스 로직의 추가라고 되어 있는데, 관점에 따라 다르게 표현 할 수 있는 것 같습니다. 비지니스 로직의 추가인데, 결과적으로 그것이 State의 변화를 다루는 코드라서 저렇게 이름을 붙여봤습니다. 지금은 코딩 관점의 이해가 좀 더 필요하니까요. 다만, State가 비지니스 로직의 핵심적인 부분이라는 점을 염두에 두면 좋겠네요.

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();
  }
}

"좋아요"로 선택 된 단어들이 저장 될 배열 변수가 추가되었고,

"종하요" 버튼을 눌렀을 때의 처리, 즉, 배열에서 추가/삭제 처리를 해주는 코드가 있네요. Like 버튼의 상태 변경은 여기서 하지 않고, 아마도 UI를 담당하는 쪽에서 조회하여 처리를 하겠죠? UI 담당하는 쪽에 '데이터가 변경 되었으니 UI를 갱신하세요.'라고 알려주기 위해 notifyListeners를 호출하고~

 Dart에서는 List형태를 []을 이용해서 표현하고, Set형태를 {}를 이용해서 표현한다고 하니 그렇다는 정도만 한번 체크 해 두고 넘어가겠습니다.

 

 

 

버튼 추가

예상처럼 버튼을 추가하기 위해 Row라는 위젯을 추가합니다. 이전과 같이 Wrap를 써서 추가하는데, 현재 설정 되어 있는 버튼을 Row로 Wrap하면 됩니다.

이렇게 Row 위젯을 추가하면, 최종 목표와는 조금 다른 모습으로 나타납니다.

 

즉, Row 자체는 중앙 정렬이 되어 있지만, 그 Row 내부에서는 기본값인 왼쪽 정렬이 되어 있습니다. 이것은 Column의 기본 정렬이 Top인 것과 같습니다. 그렇다면, 해결 방법도 같은 방법을 쓰면 되겠죠?

 

코드를 아래와 같이 정렬 코드를 추가하여 확인 해 봅니다.

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

결과는 예상과 같이 중앙 정렬이 되어 있습니다. 그런데, tutorial에서는 교육 목적을 위해 다른 속성을 사용하여 문제를 해결합니다. 즉, 한 행이 좌우로 꽉차도록 크기 때문에 왼쪽 정렬이 되었는데, 한 행의 가로 크기가 빈틈이 없도록 최소화 된다면 중앙 정렬한 것과 같은 효과가 날 것입니다.(CSS 경험이 도움이 될 것 같네요.)

 

아래와 같이 코드를 수정해도 똑같이 가운데 정렬 된 결과를 확인 할 수 있습니다.

    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의 children에 기존의 버튼과 똑같은 형식으로 넣으면 될 것 같습니다. tutorial에서도 직접 한번 해보라고 하는데, 저는 아래와 같이 작성 해 보았습니다.

   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.toggleFavorite();  
                  },
                  child: Text('Like'),
                ),
                ElevatedButton(
                  onPressed: () {
                    appState.getNext();  
                  },
                  child: Text('Next'),
                ),
              ],
            ),
          ],
        ),
      ),
    );

결과는 비슷하지만, 버튼 사이의 간격이 좀 있으면 좋겠고, 버튼 내부에 하트 표시가 없습니다.

 

정답(?)은 아래 코드와 같습니다. Icon이라는 속성을 이용하여 하트 표시를 추가 할 수 있고, SizedBox로 여백을 준 것은 이전의 예와 동일합니다. Icon은 이전에 좋아요 표시했던 단어인지 여부를 확인하여 칠이 된 하트와 테두리 하트를 할당합니다.

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,   // ← Add this.
              children: [
                // ↓ And this.
                ElevatedButton.icon(
                  onPressed: () {
                    appState.toggleFavorite();
                  },
                  icon: Icon(icon),
                  label: Text('Like'),
                ),
                SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () {
                    appState.getNext();  
                  },
                  child: Text('Next'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

결과는 아래와 같습니다.

 

하지만, next 버튼만 있기 때문에 이전에 Like 표시를 해 둔 단어들이 무엇인지 볼 방법이 지금은 없습니다.

그건 다음에 이어서 진행 됩니다.

https://learn-and-give.tistory.com/52

 

[Flutter]. 10. Flutter tutorial on codelab(6)

지난 번에 Like 버튼을 추가하였습니다. 물론, Like 표시 된 단어들을 보는 기능은 아직 만들지 않았지만, 의도 된 디자인에 맞게 코드를 수정하는 경험을 통해, 주어진 디자인을 바탕으로 어떻게

learn-and-give.tistory.com

 

 

728x90
반응형

댓글