Flutter - Quiz App

godo·2022년 6월 1일
0

Flutter

목록 보기
4/18

프로젝트 시작

flutter start project ~~~ 

패키지 설치

flutter packages get 

main.dart 코드

import 'package:flutter/material.dart';

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Text('Hello!'),);
  }
}

Format Document

방향키 위 + 옵션 + F(대문자 에프)

하면 좀 더 가독성 좋게 바뀜

두번째 main.dart 코드

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: Text('This is my default text!'),
      ),
    );
  }
}

deprecated 인 것을 사용할 때 설정

Code > Preferences > Settings > deprecated > 체크 해제

버튼 만들기 - column

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var questions = [
      'What\'s your favorite color?',
      'What\'s your favorie animal?',
    ];
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: Column(
          children: [
            Text('The question!'),
            RaisedButton(
              child: Text('Answer 1'),
              onPressed: null,
            ),
            RaisedButton(
              child: Text('Answer 2'),
              onPressed: null,
            ),
            RaisedButton(
              child: Text('Answer 3'),
              onPressed: null,
            ),
            RaisedButton(
              child: Text('Answer 4'),
              onPressed: null,
            ),
          ],
        ),
      ),
    );
  }
}

버튼에 함수 추가

class MyApp extends StatelessWidget {

  void answerQuestion() {
    print('Answer chosen!');
  }
  @override
  Widget build(BuildContext context) {
    var questions = [
      'What\'s your favorite color?',
      'What\'s your favorie animal?',
    ];
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: Column(
          children: [
            Text('The question!'),
            RaisedButton(
              child: Text('Answer 1'),
              onPressed: answerQuestion,
            ),
            RaisedButton(
              child: Text('Answer 2'),
              onPressed: () => print('Answer 2 chosen!'),
            ),
            RaisedButton(
              child: Text('Answer 3'),
              onPressed: () {
                print('Answer 3 chosen');
              },
            ),
            RaisedButton(
              child: Text('Answer 4'),
              onPressed: answerQuestion,
            ),
          ],
        ),
      ),
    );
  }
}


누르면 이런 식으로 텍스트가 뜨는 함수를 만들어 넣어 줬음

State

Stateless vs Stateful

Stateless 는 밖에서의 데이터만을 이용해서 UI를 만들고
Stateful 은 밖에서 뿐만 아니라 안에서의 데이터의 변화도 이용해서 UI를 만듬

StatefulWidget 사용

class MyApp extends StatefulWidget {
}

라는 클래스를 만들어 주고

class MyAppState extends State<MyApp> {

}

안에 전에 만들었던 코드들을 넣어주고

class MyApp extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return MyAppState();
  }
}

이런식으로 코드를 짜주면

완성됨

변화 주기

void answerQuestion() {
    setState(() {
      questionIndex = questionIndex + 1;
    });
    print(questionIndex);
  }

이런 식으로 setState 라는 함수를 이용해 줘야 변화가 적용 됨

private class

class _MyAppState

이런식으로 클래스 이름 앞에 _를 붙이면 dart 에선 private 로 인식됨

custom widget 만들기

Question.dart 파일

import 'package:flutter/material.dart';


class Question extends StatelessWidget {
//  final String questionText; // 절대로 안 바뀔 것이다 한번 할당으로 끝  
  String questionText; // 절대로 안 바뀔 것이다 한번 할당으로 끝  

  Question(this.questionText);

  @override
  Widget build(BuildContext context) {
    return Text(questionText);
  }
}

main.dart 파일에 적용

	Question(
              questions[_questionIndex]
            ),

style, layout

 @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      margin: EdgeInsets.all(10),
      child: Text(
        questionText, 
        style: TextStyle(fontSize: 30),
        textAlign: TextAlign.center,
      ),
    ); 
  }

Callback Functions

answer.dart

import 'package:flutter/material.dart';

class Answer extends StatelessWidget {
  final VoidCallback selectHandler;

  Answer(this.selectHandler);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      child :RaisedButton(
              color: Color.fromARGB(255, 36, 109, 168),
              child: Text('Answer 1'),
              onPressed: selectHandler,
            ),
    );
  }
}

main.dart

import './answer.dart';

...

Answer(_answerQuestion),

질문과 답 동적으로 주기

main.dart

import 'package:flutter/material.dart';

import './question.dart';
import './answer.dart';

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

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

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  var _questionIndex = 0;

  void _answerQuestion() {
    setState(() {
      _questionIndex = _questionIndex + 1;
    });
    print(_questionIndex);
  }

  @override
  Widget build(BuildContext context) {
    var questions = [
      {
        'questionText': 'What\'s your favorite color?',
        'answers': ['Black', 'Pink', 'Purple', 'Orange'],
      },
      {
        'questionText': 'What\'s your favorite animal?',
        'answers': ['Rabbit', 'Lion', 'Elephant', 'Dog'],
      },
      {
        'questionText': 'What\'s your favorite name?',
        'answers': ['Max', 'Chris', 'Jake', 'Mina'],
      },
    ];
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: Column(
          children: [
            Question(
              questions[_questionIndex]['questionText'] as String,
            ),
            ...(questions[_questionIndex]['answers'] as List<String>)
                .map((answer) {
              return Answer(_answerQuestion, answer);
            }).toList() // ... 은 리스트 내부를 밖으로 꺼내 주는 것 
          ],
        ),
      ),
    );
  }
}

answer.dart

import 'package:flutter/material.dart';

class Answer extends StatelessWidget {
  final VoidCallback selectHandler;
  final String answerText;

  Answer(this.selectHandler, this.answerText);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      child :RaisedButton(
              color: Color.fromARGB(255, 36, 109, 168),
              textColor: Colors.white,
              child: Text(answerText),
              onPressed: selectHandler,
            ),
    );
  }
}

Null Safety

pubspec.yaml 에서
environment :
sdk : ">=2.12.0" 이상이면 Null Safety 켜짐
sdk : ">=2.11.0" 이면 Null Safety 꺼짐

Optional

String? userName = "max";

userName = null; 

// null 값을 줄 수 있음 ?이 없으면 줄 수 없음 

3항 연산자 사용하여 앱 구성

body: _questionIndex < questions.length ? Column(
          children: [
            Question(
              questions[_questionIndex]['questionText'] as String,
            ),
            ...(questions[_questionIndex]['answers'] as List<String>)
                .map((answer) {
              return Answer(_answerQuestion, answer);
            }).toList() // ... 은 리스트 내부를 밖으로 꺼내 주는 것 
          ],
        ) : Center(child: Text('You did it!'),),

split widget

quiz.dart

import 'package:flutter/material.dart';
import './question.dart';
import './answer.dart';

class Quiz extends StatelessWidget {
  final List<Map<String, Object>> questions;
  final int questionIndex;
  final VoidCallback answerQuestion;

  Quiz({
    @required this.questions, 
    @required this.answerQuestion, 
    @required this.questionIndex
    });

  @override
  Widget build(BuildContext context) {
    return Column(
          children: [
            Question(
              questions[questionIndex]['questionText'] as String,
            ),
            ...(questions[questionIndex]['answers'] as List<String>)
                .map((answer) {
              return Answer(answerQuestion, answer);
            }).toList() // ... 은 리스트 내부를 밖으로 꺼내 주는 것 
          ],
        );
  }
}

result.dart

import 'package:flutter/material.dart';


class Result extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('You did it!'),
    );
  }
}

main.dart


... 

class _MyAppState extends State<MyApp> {
  final _questions = [
      {
        'questionText': 'What\'s your favorite color?',
        'answers': ['Black', 'Pink', 'Purple', 'Orange'],
      },
      {
        'questionText': 'What\'s your favorite animal?',
        'answers': ['Rabbit', 'Lion', 'Elephant', 'Dog'],
      },
      {
        'questionText': 'What\'s your favorite name?',
        'answers': ['Max', 'Chris', 'Jake', 'Mina'],
      },
    ];

  var _questionIndex = 0;

  void _answerQuestion() {

    if (_questionIndex < _questions.length) {
      setState(() {
        _questionIndex = _questionIndex + 1;
      });
    } else {
      // _questionIndex = 0;
      print('No more questions!');
    }
    print(_questionIndex);
  }

  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First App'),
        ),
        body: _questionIndex < _questions.length 
        ? Quiz(answerQuestion: _answerQuestion, questions: _questions, questionIndex: _questionIndex,)
        : Result(),
      ),
    );
  }
}

스코어

main.dart

final _questions = [
      {
        'questionText': 'What\'s your favorite color?',
        'answers': [
          {'text': 'Black', 'score':10}, 
          {'text':'Pink', 'score':7}, 
          {'text': 'Purple', 'score':5}, 
          {'text':'Orange', 'score':3}
        ],
      },
      {
        'questionText': 'What\'s your favorite animal?',
        'answers': [
            {'text':'Rabbit', 'score':10}, 
            {'text':'Lion', 'score':7}, 
            {'text':'Elephant','score':5}, 
            {'text':'Dog','score':3}
          ],
      },
      {
        'questionText': 'What\'s your favorite name?',
        'answers': [
            {'text':'Max','score':10}, 
            {'text':'Chris','score':7}, 
            {'text':'Jake','score':5}, 
            {'text':'Mina','score':3}
          ],
      },
    ];

quiz.dart

@override 
Widget build(BuildContext context) {
    return Column(
          children: [
            Question(
              questions[questionIndex]['questionText'] as String,
            ),
            ...(questions[questionIndex]['answers'] as List<Map<String, Object>>)
                .map((answer) {
              return Answer(() => answerQuestion(answer['score']), answer['text'] as String);
            }).toList() // ... 은 리스트 내부를 밖으로 꺼내 주는 것 
          ],
        );
  }

result.dart , get

import 'package:flutter/material.dart';


class Result extends StatelessWidget {

  final int resultScore;

  Result(this.resultScore);

  String get resultPhrase { // get
    var resultText;
    
    if (resultScore <= 8) {
      resultText = 'You are awesome and innocent!';
    } else if (resultScore <= 12) {
      resultText = 'Pretty likeale!';
    } else if (resultScore <= 16) {
      resultText = 'You are ... strange?!';
    } else {
      resultText = 'You are so bad!';
    }

    return resultText;
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
          resultPhrase, 
          style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
          textAlign: TextAlign.center,
        ),
    );
  }
}

restart quiz 버튼, 및 기능

main.dart

void _resetQuiz() {

    setState(() {
      _questionIndex = 0;
      _totalScore = 0;
    });
  }

...


Result(_totalScore, _resetQuiz),

result.dart

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          Text(
              resultPhrase, 
              style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
              textAlign: TextAlign.center,
            ),
            FlatButton(
                onPressed: resetQuiz, 
                child: Text('Restart Quiz!'),
                textColor: Colors.blue,
              )
        ],
      ),
    );
  }

새 버튼 ( New Button )

RaisedButton > ElevatedButton

예전 꺼는 인자로 변경할 수 있지만, 새것은 style를 통해서 ButtonStyle() 로 해줘야 함
style : ButtonStyle() ... 이런식으로

style: ButtonStyle(
	backgroundColor : MaterialStateProperty.all(Colors.orange),
    foregroundColor : MaterialStateProperty.all(Colors.white),
),

이렇게

style: ElevatedButton.styleForm(primary: Colors.blue, onPrimary: Colors.white),

아님 이렇게 해줄 수 있음

FlatButton > TextButton

이것도 위와 비슷함

근데 여기선 primary가 글자 색깔임 ... 백그라운드 컬러가 없기 때문

OutlineButton > OutlinedButton

style: BorderStyle(~~)
OutlinedButton.styleForm(
	primary: Colors.orange, 
	side: BorderSide(color: Colors.orange),
    )

여기도 primary 밖에 없음 , side 는 선 색깔

Github

https://github.com/godo129/Flutter_quiz_app

profile
☀️☀️☀️

0개의 댓글