[flutter] 유데미x스나이퍼팩토리 프로젝트 캠프 - 7일차 학습일지 - 2: 단어 앱 제작

손세은·2023년 9월 28일

< 6일차 과제 요구 사항 >

  • 제공되는 단어데이터를 활용하여 다음의 UI를 만들어주세요.**
  • 단어 데이터 확인하기 (기본 5개이며 추가가능, 본인의 단어 데이터 활용가능)
List<Map<String, String>> words = [
  {
		"word": "apple", 
		"meaning": "사과", 
		"example": "I want to eat an apple"
	},
  {
		"word": "paper", 
		"meaning": "종이", 
		"example": "Could you give me a paper"
	},
  {
    "word": "resilient",
    "meaning": "탄력있는, 회복력있는",
    "example": "She's a resilient girl"
  },
  {
    "word": "revoke",
    "meaning": "취소하다",
    "example": "The authorities have revoked their original decision to allow development of this rural area."
  },
  {
    "word": "withdraw",
    "meaning": "철회하다",
    "example": "After lunch, we withdrew into her office to finish our discussion in private."
  },
];

Requirements
1. FloatingActionButton이 두 개가 떠있는 형태로, 양쪽에 위치합니다.
- 왼쪽 버튼을 클릭하면, 이 전 단어로 이동합니다.
- 오른쪽 버튼을 클릭하면, 이 다음 단어로 이동합니다.
2. ThemeData.dark() 를 활용합니다.
3. 단어와 뜻의 자간을 -1만큼 좁혀봅니다. 예문은 1만큼의 자간을 갖도록 합니다.
4. 단어는 최소 5개 이상으로 준비합니다.

1. 위젯 및 속성

  1. floatingActionButton은
    Row, Column을 사용해서 2개로 놓을 수 있다.!
  2. PageView.builder
  3. PageContoller
  4. style: letterSpacing = 자간을 좁히는 방법!
  • 자세한건 requirements 해결을 참고하자.

2. 앱 코드

  • lib/main.dart
import 'package:day7_word_app/word_app.dart';
import 'package:flutter/material.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: WordApp(),
    );
  }
}
  • lib/word_app.dart
import 'package:day7_word_app/Widget/word_page_widget.dart';
import 'package:flutter/material.dart';

class WordApp extends StatefulWidget {
  const WordApp({super.key});

  
  State<WordApp> createState() => _WordAppState();
}

class _WordAppState extends State<WordApp> {
  var _pageController = PageController();

  List<Map<String, dynamic>> words = [
    {
      'word': 'apple',
      'meaning': '사과',
      'example': '"I want to eat an apple"',
    },
    {
      'word': 'paper',
      'meaning': '종이',
      'example': '"Could you give me a paper"',
    },
    {
      'word': 'resilent',
      'meaning': '탄력있는, 회복력 있는',
      'example': '"she\'s a resilent girl"',
    },
    {
      'word': 'revoke',
      'meaning': '취소하다',
      'example':
          '"The authorities have revoked their original decision to allow development of this rural area."',
    },
    {
      'word': 'withdraw',
      'meaning': '철회하다',
      'example':
          '"After lunch, we withdraw into her office to finish our discussion in private."',
    }
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView.builder(
        controller: _pageController,
        physics: NeverScrollableScrollPhysics(),
        itemCount: 5, // 페이지 개수
        itemBuilder: (BuildContext context, int index) {
          // 각 페이지의 콘텐츠를 생성하는 빌더 함수
          return WordPageWidget(
            word: words[index]['word'],
            meaning: words[index]['meaning'],
            example: words[index]['example'],
          );
        },
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Row(
          children: [
            FloatingActionButton(
              onPressed: () {
                _pageController.previousPage(
                  duration: Duration(milliseconds: 500),
                  curve: Curves.linear,
                );
              },
              child: Icon(Icons.arrow_back_ios_new),
            ),
            Spacer(),
            FloatingActionButton(
              onPressed: () {
                _pageController.nextPage(
                  duration: Duration(milliseconds: 500),
                  curve: Curves.linear,
                );
              },

              child: Icon(Icons.arrow_forward_ios),
            ),
          ],
        ),
      ),
    );
  }
}

  • lib/Widget/WordPageWidget.dart
import 'package:flutter/material.dart';

class WordPageWidget extends StatefulWidget {
  final String word;
  final String meaning;
  final String example;

  const WordPageWidget(
      {super.key,
      required this.word,
      required this.meaning,
      required this.example});

  
  State<WordPageWidget> createState() => _WordPageWidgetState();
}

class _WordPageWidgetState extends State<WordPageWidget> {
  
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text(
            '${widget.word}',
            style: TextStyle(
                fontSize: 50, fontWeight: FontWeight.bold, letterSpacing: -1),
          ),
          Text(
            '${widget.meaning}',
            style: TextStyle(
              color: Colors.grey,
              fontSize: 24,
              letterSpacing: -1,
            ),
          ),
          SizedBox(height: 15),
          Text(
            '${widget.example}',
            textAlign: TextAlign.center,
            style: TextStyle(
              fontSize: 18,
              color: Colors.grey,
            ),
          ),
        ],
      ),
    );
  }
}

3. Requirements 해결

  1. FloatingActionButton이 두 개가 떠있는 형태로, 양쪽에 위치합니다.
    • 왼쪽 버튼을 클릭하면, 이 전 단어로 이동합니다.
    • 오른쪽 버튼을 클릭하면, 이 다음 단어로 이동합니다.
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      //FAB는 전체적으로 살짝 왼쪽으로 치우치게 설정 되어 있기 때문에 //가운데로 설정해준다. 
      floatingActionButton: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Row(
        //floatingActionButton에는 위젯을 넘겨주기만 하면 되기 때문에,
        //2개로 나열할 수 있게 Row를 사용한다. 
          children: [
            FloatingActionButton(
              onPressed: () {
                _pageController.previousPage(
                //pageView.builder에도 controller 속성이 있음. 연결하여 사용한다 
                  duration: Duration(milliseconds: 500),
                  curve: Curves.linear,
                );
              },
              child: Icon(Icons.arrow_back_ios_new),
            ),
            Spacer(),
            FloatingActionButton(
              onPressed: () {
                _pageController.nextPage(
                  duration: Duration(milliseconds: 500),
                  curve: Curves.linear,
                );
              },
  1. ThemeData.dark() 를 활용합니다.
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: WordApp(),
    );
  }
}
  1. 단어와 뜻의 자간을 -1만큼 좁혀봅니다. 예문은 1만큼의 자간을 갖도록 합니다.
          Text(
            '${widget.meaning}',
            style: TextStyle(
              color: Colors.grey,
              fontSize: 24,
              letterSpacing: -1,
            ),
          )
  • 자간 : 글자 사이의 간격
  • Text(style: ) 속성의 letterSpacing 을 사용한다. 자간 -1
  1. 단어는 최소 5개 이상으로 준비합니다.
PageView.builder(
        controller: _pageController,
        physics: NeverScrollableScrollPhysics(),
        itemCount: words.length, // 페이지 개수
        itemBuilder: (BuildContext context, int index) {
          // 각 페이지의 콘텐츠를 생성하는 빌더 함수
          return WordPageWidget(
            word: words[index]['word'],
            meaning: words[index]['meaning'],
            example: words[index]['example'],
          );
        },
      )
  • PageView.builder에 위젯을 연결하고,
    <List> words = [{5개의 데이터}] 를 사용하였다.

4. 결과





profile
힙스터 개발자가 될래요

0개의 댓글