공부 기록/Flutter

Flutter: 로그인 & 주사위 게임 실습

naraewool 2021. 11. 27. 18:37
728x90

https://www.youtube.com/watch?v=mQX_kJKnZzk&list=PLQt_pzi-LLfoOpp3b-pnnLXgYpiFEftLB&index=3

SingleChildScrollView 위젯은. 키보드 입력 시 화면이 잘려보이기 때문에 스크롤할 수 있도록 Column위젯을 해당 위젯으로 감쌈. 

 

https://flutter.dev/docs/cookbook/forms/text-field-changes#2-use-a-texteditingcontroller

 

Handle changes to a text field

How to detect changes to a text field.

docs.flutter.dev

TextEditingController: 텍스트 폼에 입력한 데이터를 가지고 오는

생성자 생성한 후에 해당 변수 이름을 TextForm의 인자로 전달해주어야 함: controller: {NAME} -> 해당 텍스트폼에 입력한 데이터를 가지고옴

 

복습 18, 19, 22  -> done

 

https://www.youtube.com/watch?v=mmR2u8TgoCk&list=PLQt_pzi-LLfoOpp3b-pnnLXgYpiFEftLB&index=7 

키보드가 아닌 화면을 누르면 키보드가 사라지는 기능을 구현해보자. 이럴 때 GestureDetecter 위젯 사용.(사용자의 행동을 감지하는 위젯 . 길게 누르기 연속 두번 누르기 등의 액션)

화면의 빈 곳이 사용자의 액션에 반응하는 버튼처럼 작동해야하므로 SingleChildScroolView에 위젯으로 감싸고, 

 그 중에서 빈 화면을 탭했을 때 반응하는 기능을 위해 onTap() method 이용.

텍스트 필드는 다음 Focus와 관련이 있다. 무엇일까?

FocusScope.of(context): 이것을 통해 현재 텍스트 필드와 연결되어 있는 포커스 노드를 찾을 수 있다. (참고)
그리고 unfucs() method가 포커스를 없애고 키보드를 사라지게 한다. 

 

FocusScope class - widgets library - Dart API

A FocusScope is similar to a Focus, but also serves as a scope for its descendants, restricting focus traversal to the scoped controls. For example a new FocusScope is created automatically when a route is pushed, keeping the focus traversal from moving to

api.flutter.dev

 body: Builder(
          builder: (context){
          return GestureDetector(
            onTap: (){  // 사용자가 빈 곳을 누를때 작동하는 함수
              FocusScope.of(context).unfocus(); // 해당 포커스의 범위가 포커스에서 해제된다(unfocus)
            },

포커스를 받는 텍스트 필드가 없어야 올라와있는 키보드를 내려가게 할 수 있다? 

 

Colum이나 Row 위젯 내의 요소를 정렬할때는 mainAxisAlignment를 이용하자. 

      body: Center(
        child: Column(
          // crossAxisAlignment:  CrossAxisAlignment.center, -> 이거 대신 Row widget에서 한번 더 정렬해주어야함.
          mainAxisAlignment: MainAxisAlignment.center, // 주축 정렬 설정, 즉 cloum의 주축인 세로축 정렬 설정 -> 중앙
          children: <Widget> [
            Row(
              mainAxisAlignment: MainAxisAlignment.center, // 가로축으로 중앙
              children: [
                Image.asset('image/dice1.png')
                // Image(   이렇게 구현하는 것보다 위와 같이 Image.asset을 이용하면 더 간단 
                //   image: AssetImage('image/dice1.png'),
                //   width: 300.0,
                //   //alignment: Alignment.center -> 가운데 정렬이 이거라고 생각했는 Colmun 위젯에서 정렬은 mainAxisAlignment 위젯을 사용해야함
                // )
              ],

Expanded 위젯은 해당 공간(여기서는 Row)에 맞도록 요소를 확장하는 기능을 한다. Row에 두 개의 이미지를 배치하고 그 이미지들이 Row내에 가득차도록 확장.

flex 속성을 이용할 수도 있음

둘의 간격을 조정하려면 Padding widget으로 감싸기

 

마지막으로 left/rightDice 변수를 선언하고, Random함수를 이용하여 임의의 숫자가 나오도록 한다. 이 때 dart: math;를 임포트해주어야 한다.

import 'dart:math';

class _DiceState extends State<Dice> {

  int leftDice = 1;
  int rightDice = 1;
  
.
.

onPressed: (){
 setState( () {
   leftDice = Random().nextInt(6) + 1;
   rightDice = Random().nextInt(6) + 1;
 });
 showToast("Left dice: {$leftDice}, Right dice: {$rightDice}");
 },

임의의 숫자에 따라 보여지는 이미지들도 다르게 보이도록 Expanded(child: Image.asset('image/dice$leftDice.png')) 으로 변경해준다. 이 때는 {}을 안 써줘도 되는군.

dice.dart 파일의 전체 코드

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:fluttertoast/fluttertoast.dart'; // toast 메시지 구현을 위한 라이브러리

class Dice extends StatefulWidget {
  @override
  State<Dice> createState() => _DiceState();
}

class _DiceState extends State<Dice> {

  int leftDice = 1;
  int rightDice = 1;


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.redAccent,
      appBar: AppBar(
        backgroundColor: Colors.redAccent,
        title: Text('Dice game'),
      ),
      body: Center(
        child: Column(
          // crossAxisAlignment:  CrossAxisAlignment.center, -> 이거 대신 Row widget에서 한번 더 정렬해주어야함.
          mainAxisAlignment: MainAxisAlignment.center, // 주축 정렬 설정, 즉 Column 주축인 세로축 정렬 설정 -> 중앙
          children: <Widget> [
            Padding( // 주사위가 있는 Row의 간격을 조절하기 위하여 Padding widget으로 감쌈
              padding: EdgeInsets.all(32.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center, // 가로축으로 중앙정렬
                children: [
                  Expanded(child: Image.asset('image/dice$leftDice.png')),
                  SizedBox(width: 20.0,), // 주사위 사이에 간격 조절
                  Expanded(child: Image.asset('image/dice$rightDice.png'))
                ],
              ),
            ),
            SizedBox(
              width: 60.0,
            ),
            ButtonTheme(
              minWidth: 88.0,
              height: 60.0,
              buttonColor: Colors.orangeAccent,
              hoverColor: Colors.white,
              child: ElevatedButton(
                child: Icon(
                  Icons.play_arrow,
                  color: Colors.white,
                  size: 50.0,
                ),
                 onPressed: (){
                  setState( () {
                    leftDice = Random().nextInt(6) + 1;
                    rightDice = Random().nextInt(6) + 1;
                  });
                  showToast("Left dice: {$leftDice}, Right dice: {$rightDice}");
                  },
               ),
              ),
          ],
        )
      ),
    );
  }
}

void showToast(String msg){
  Fluttertoast.showToast(
    msg: msg,
    backgroundColor: Colors.white,
    toastLength: Toast.LENGTH_SHORT,
    gravity: ToastGravity.TOP_LEFT);
}

 

이로써 샘플앱을 드디어 완성했다 :)
너무나 쉽게 그리고 가장 기본적인 개념들도 잘 잡아주신 코딩쉐프님 덕에 이번 실습은 포기하지 않고 끝까지 할 수 있게되었다. 감사합니다!!!