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