본문 바로가기

개발(합니다)/Flutter&android&ios

[flutter-13] 로그인과 주사위 놀이 만들기(위젯 리팩토링, future, async, await)

반응형

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

import 'dice.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Dice game',
      home: LogIn(),
    );
  }
}

class LogIn extends StatefulWidget {
  @override
  _LogInState createState() => _LogInState();
}

class _LogInState extends State<LogIn> {
  TextEditingController controller = TextEditingController();
  TextEditingController controller2 = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Log in"),
        backgroundColor: Colors.redAccent,
        centerTitle: true,
        leading: IconButton(
          icon: Icon(Icons.menu),
          onPressed: () {},
        ),
        actions: [IconButton(icon: Icon(Icons.search), onPressed: () {})],
      ),
      body: Builder(
        builder: (context) {
          return GestureDetector(
            // 빈화면을 눌렀을 때 발생할 이벤트
            onTap: () {
              // Focus tree :
              // Focus node : 포커스를 받는 특정 위젯을 식벽,
              // Focus Scope : 어떤 위젯들까지 포커스를 받을 수 있는지 나타냄
              FocusScope.of(context).unfocus();
            },
            child: SingleChildScrollView(
              child: Column(
                children: [
                  Padding(padding: EdgeInsets.only(top: 10)),
                  Center(
                    child: Image(
                        image: AssetImage('assets/images/2.gif'),
                        height: 170,
                        width: 190.0),
                  ),
                  Form(
                      child: Theme(
                    data: ThemeData(
                        primaryColor: Colors.teal,
                        inputDecorationTheme: InputDecorationTheme(
                            // 사용자에게 정보를 주는 레이블
                            labelStyle:
                                TextStyle(color: Colors.teal, fontSize: 15.0))),
                    child: Container(
                      padding: EdgeInsets.all(40.0),
                      child: Column(
                        children: [
                          TextField(
                            autofocus: true,
                            decoration:
                                InputDecoration(labelText: "Enter dice"),
                            keyboardType: TextInputType.emailAddress,
                            // 키보드 입력 타입
                            controller: controller,
                          ),
                          TextField(
                            decoration:
                                InputDecoration(labelText: "Enter password"),
                            keyboardType: TextInputType.text, // 키보드 입력 타입
                            obscureText: true, // 비밀번호 안보이게 처리
                            controller: controller2,
                          ),
                          SizedBox(
                            height: 40.0,
                          ),
                          ButtonTheme(
                            minWidth: 100.0,
                            height: 50.0,
                            child: RaisedButton(
                              onPressed: () {
                                if (controller.text == "dice" &&
                                    controller2.text == '1234') {
                                  Navigator.push(
                                      // 페이지 이동
                                      context,
                                      MaterialPageRoute(
                                        builder: (context) => Dice(),
                                      ));
                                } else {
                                  showSnackBar(context);
                                }
                              },
                              color: Colors.orange,
                              child: Icon(
                                Icons.arrow_forward,
                                color: Colors.white,
                                size: 35.0,
                              ),
                            ),
                          )
                        ],
                      ),
                    ),
                  ))
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

void showSnackBar(BuildContext context) {
  Scaffold.of(context).showSnackBar(SnackBar(
    content: Text(
      "로그인 정보를 확인해주세요",
      textAlign: TextAlign.center,
    ),
    duration: Duration(seconds: 2),
    backgroundColor: Colors.blue,
  ));
}
  • dice.dart
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:fluttertoast/fluttertoast.dart';

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

class _DiceState extends State<Dice> {
  int leftDice = 2;
  int rightDice = 5;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.redAccent,
      appBar: AppBar(
        backgroundColor: Colors.redAccent,
        title: Text("Die game"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Padding(
              padding: EdgeInsets.all(32),
              child: Row(
                // mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: 주축 정렬
                children: [
                  // Image(
                  //   image: AssetImage("assets/images/dice1.png"),
                  //   width: 300.0,
                  // )
                  Expanded(
                      // 이미지를 공간안에서 확장해줌
                      // flex: 2,
                      child: Image.asset("assets/images/dice$leftDice.png")),
                  // 간편하게 이미지 호출 가능
                  SizedBox(
                    width: 20.0,
                  ),
                  Expanded(
                      // flex: 1, // 크기를 대비하는 기능
                      child: Image.asset('assets/images/dice$rightDice.png')),
                  // 간편하게 이미지 호출 가능
                ],
              ),
            ),
            SizedBox(
              height: 60.0,
            ),
            ButtonTheme(
                minWidth: 100.0,
                height: 60,
                child: RaisedButton(
                  child: Icon(
                    Icons.play_arrow,
                    color: Colors.white,
                    size: 50.0,
                  ),
                  onPressed: () {
                    setState(() {
                      leftDice = Random().nextInt(6) + 1; // 0부터 5까지이므로 +1을 해줌
                      // print(leftDice);
                      rightDice = Random().nextInt(6) + 1;
                      // print(rightDice);
                    });
                    showToastMessage("left dice : $leftDice, right dice : $rightDice");

                  },
                  color: Colors.orangeAccent,
                ))
          ],
        ),
      ),
    );
  }
}

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

주요 기능

  • TextEditingController controller = TextEditingController(); : TextField 값 받기
  • return GestureDetector( : 사용자의 제스처를 어떻게 할지 정하는 위젯
  • FocusScope.of(context).unfocus(); : 포커스를 벗어나게 하는 기능
  • child: SingleChildScrollView( : 하나의 스크롤을 가지는 뷰 위젯
  • Form( : 입력 폼을 가지는 위젯
  • data: ThemeData( : 테마를 지정하고 꾸밀수 있게 해주는 위젯
  • TextField( : 입력 필드를 만드는 위젯
  • ButtonTheme( : 버튼의 테마를 지정하고 꾸밀 수 있게 해주는 위젯
  • Expanded( : 공간을 최대한 가득차게 하거나 조절할 수 있는 위젯
  • child: Image.asset("assets/images/dice$leftDice.png")), 이미지를 쉽게 불러올 수 있는 위젯

위젯 리펙토링

  • main2.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'login.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Firebase login app",
      home: Login(),
    );
  }
}
  • login.dart
import 'package:flutter/material.dart';
import 'package:week4_app/my_button/my_button.dart';

class Login extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue,
        title: Text(
          "Sign In",
          style: TextStyle(color: Colors.white),
        ),
        centerTitle: true,
        elevation: 0.2,
      ),
      body: _buildButton(), // private은 같은 파일에서만 접근 가능
    );
  }

  Widget _buildButton() {
    return Padding(
      padding: EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          SizedBox(
            height: 10.0,
          ),
          ButtonTheme(
            height: 50.0,
            child: RaisedButton(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  Image.asset(
                    'assets/images/facebook.png',
                    width: 30,
                  ),
                  Text(
                    "login with facebook",
                    style: TextStyle(color: Colors.black87, fontSize: 15),
                  ),
                  Opacity(
                    opacity: 0.0,
                    child: Image.asset(
                      "assets/images/facebook.png",
                      width: 30,
                    ),
                  )
                  // 간격을 맞추기 위해 임시로 만듬 투명도를 조정하는 위젯
                ],
              ),
              color: Colors.white,
              onPressed: () {},
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(Radius.circular(4.0))),
            ),
          ),
          SizedBox(
            height: 10.0,
          ),
          MyButton(
            image: Image.asset(
              'assets/images/google.png',
              width: 30.0,
            ),
            text: Text(
              "login with google",
              style: TextStyle(color: Colors.black87, fontSize: 15.0),
            ),
            radius: 4.0,
            color: Colors.white,
            onPressed: (){},
          ),
          SizedBox(
            height: 10.0,
          ),
          ButtonTheme(
            height: 50.0,
            child: RaisedButton(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  Image.asset(
                    'assets/images/email.png',
                    width: 30,
                  ),
                  Text(
                    "login with email",
                    style: TextStyle(color: Colors.black87, fontSize: 15),
                  ),
                  Opacity(
                    opacity: 0.0,
                    child: Image.asset(
                      "assets/images/email.png",
                      width: 30,
                    ),
                  )
                  // 간격을 맞추기 위해 임시로 만듬 투명도를 조정하는 위젯
                ],
              ),
              color: Colors.white,
              onPressed: () {},
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(Radius.circular(4.0))),
            ),
          ),
        ],
      ),
    );
  }
}
  • my_button.dart
import 'package:flutter/material.dart';
import 'package:week4_app/login_app/login.dart';

class MyButton extends StatelessWidget {
  final Widget image;
  final Widget text;
  final Color color;
  final double radius;
  final VoidCallback onPressed;

  MyButton({this.image, this.text, this.color, this.radius, this.onPressed});

  @override
  Widget build(BuildContext context) {
    // final Login login = new Login(); // private 테스트
    // login.bu
    return ButtonTheme(
      height: 50.0,
      child: RaisedButton(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            image,
            text,
            Opacity(
              opacity: 0.0,
              child: Image.asset(
                "assets/images/google.png",
                width: 30,
              ),
            )
            // 간격을 맞추기 위해 임시로 만듬 투명도를 조정하는 위젯
          ],
        ),
        color: color,
        onPressed: onPressed,
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(Radius.circular(radius))),
      ),
    );
  }
}

Future, async, await

  • Future 클래스는 비동기 작업의 경우 사용
  • Future 클래스는 일정 소요 시간 후에 실제 데이터나 에러를 반환
  • async 클래스는 await 메서드를 가지고 있으며 await 메서드는 응답이 처리 될 때까지 대기
import 'dart:io';

main() {
  showData();
}

void showData() async{
  startTask();
  String s = await accessData();
  fatchData(s);
}

void fatchData(String account) {
  print("fatchData $account");
}

Future<String> accessData() async{
  String account;
  Duration time = Duration(seconds: 3);
  if (time.inSeconds > 2) {
    // sleep(time);

    await Future.delayed(time, () {
      account = '8500원';
      print("accessData dd : $account ");
    }); // 비동기 처리

  } else {
    print("accessData");
  }
  return account;
}

void startTask() {
  print("startTask");
}
반응형