คลาส Map() ใช้สร้างแมพหรือดิกชันนารี ที่เก็บค่า key:value หรือจะสร้างจาก { } ก็ได้
เราจะสร้างรายการคำถาม 4 คำถาม แต่ละคำถามมี 4 คำตอบ ด้วยแมพดังนี้
var questions = [
{
'question': 'คุณชอบสีอะไร',
'answer': ['แดง', 'ดำ', 'น้ำเงิน', 'ขาว']
},
{
'question': 'สัตว์เลี้ยงที่ชื่นชอบคือออะไร',
'answer': ['แมว', 'กระต่าย', 'นกแก้ว', 'เสือ']
},
{
'question': 'ชอบอาหารอะไรที่สุด',
'answer': ['ซุบเนื้อ', 'ต้มยำกุ้ง', 'กะเพราไก่', 'ไข่เจียว']
},
{
'question': 'ภาษาคอมที่ชื่นชอบคืออะไร',
'answer': ['dart', 'python', 'c++', 'swift']
}
];
ในการแสดงคำถาม ให้เรียกใช้วิดเจ็ต Question ให้ส่ง String คำถามเหมือนเดิม โดยเลือกจากคีย์ question ของแมพ
main.dartchildren: [ // List Question( // widget questions[_questionId]['question'], ), Answer() ],
ในการแสดงคำตอบ ให้เลือกรายการคำตอบ answer List จาก _questionId ของรายการคำถาม questions List
main.dart
children: [ // List
Question( // widget
questions[_questionId]['question'],
),
questions[_questionId]['answer'].map((answer) { // map
return Answer(answer);
})
],
toList() converts map into List children: [ // List Question( questions[_questionId]['question'], ), (questions[_questionId]['answer'] as Listspread operator ...).map((answer) { // List of widget return Answer(answer); }).toList(), // List in a List ],
children: [ // List Question( questions[_questionId]['question'], ), ...(questions[_questionId]['answer'] as List).map((answer) { // widget return Answer(answer); }).toList(), // item of List ],
แก้ไข constructor ของวิดเจ็ต Answer ให้รับพารามิเตอร์สองตัวคือฟังก์ชัน Function และคำตอบ String
และส่งคำตอบ answer ไปเป็นพารามิเตอร์ของ Text widget
class Answer extends StatelessWidget {
final Function handler;
final String answer;
Answer(this.handler, this.answer);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: Colors.orange,
child: ElevatedButton(
onPressed: handler,
child: Text(answer),
style: ElevatedButton.styleFrom(
primary: Colors.blue, // background
onPrimary: Colors.black, // foreground
),
),
);
}
}
main.dart
ส่งพารามิเตอร์ฟังก์ชัน Function และคำตอบ String ไปยังวิดเจ็ต Answer
children: [ Question( questions[_questionId]['question'], ), ...(questions[_questionId]['answer'] as List).map((answer) { return Answer(_answer, answer); // Widget(Function, String) }).toList(), ],




ตรวจสอบเงื่อนไข เมื่อตอบครบทุกคำถาม แสดงข้อความกึ่งกลางหน้าจอด้วย Center() พร้อมปุ่มกดให้เริ่มใหม่
class _MyAppState extends Statemain.dart{ var questions = [ { 'question': 'คุณชอบสีอะไร', 'answer': ['แดง', 'ดำ', 'น้ำเงิน', 'ขาว'] }, { 'question': 'สัตว์เลี้ยงที่ชื่นชอบคือออะไร', 'answer': ['แมว', 'กระต่าย', 'นกแก้ว', 'เสือ'] }, { 'question': 'ชอบอาหารอะไรที่สุด', 'answer': ['ซุบเนื้อ', 'ต้มยำกุ้ง', 'กะเพราไก่', 'ไข่เจียว'] }, { 'question': 'ภาษาคอมที่ชื่นชอบคืออะไร', 'answer': ['dart', 'python', 'c++', 'swift'] } ]; ... }
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My App Bar'),
),
body: _questionId < questions.length
? Column(
children: [
Question(
questions[_questionId]['question'],
),
...(questions[_questionId]['answer'] as List)
.map((answer) {
return Answer(_answer, answer);
}).toList(),
],
)
: Center(
child: ElevatedButton(
child:
Text('Done!, $_questionId questions. Click to restart'),
onPressed: _answer),
),
),
);
main.dart
void _answer() {
if (_questionId == questions.length) _questionId = -1;
setState(() {
_questionId += 1;
});
print(_questionId);
}

เมื่อวิดเจ็ตเริ่มซับซ้อน เช่นวิดเจ็ต Column() ซึ่งมีหลายๆคำสั่งหรือฟังก์ชัน อยู่ในวิดเจ็ต เราสามารถแยก Column() ออกไปเป็นวิดเจ็ตใหม่ เพื่อให้โปรแกรมดูกระชับขึ้น

ให้ทำตามขั้นตอนดังนี้
import 'package:flutter/material.dart';
import './question.dart';
import './answer.dart';
class Quiz extends StatelessWidget {
final List
import 'package:flutter/material.dart';
class Restart extends StatelessWidget {
final Function handler;
final int questionId;
Restart(this.questionId,this.handler);
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: Text('Done!, $questionId questions. Click to restart'),
onPressed: handler),
);
}
}
import 'package:flutter/material.dart';
import './quiz.dart';
import './restart.dart';
...
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My App Bar'),
),
body: _questionId < _questions.length
? Quiz(
handler: _answer,
questions: _questions,
questionId: _questionId,
)
: Restart(
_questionId,
_answer,
)),
);
}
...
run app ควรจะได้ผลลัพธ์เหมือนเดิม


ในกรณีนีที่เป็นการถามความพึงพอใจ หรือการสอบ เราสามารถให้คะแนนจากแต่ละคำตอบได้
ถ้าถามคความพึงพอใจ แต่ละคำตอบก็จะมีคะแนนต่างๆกันไป
ถ้าเป็นการสอบ ก็จะมีคะแนนเฉพาะคำตอบที่ถูกต้อง
เมื่อจบการถามตอบก็สรุปคะแนน

ให้ทำตามขั้นตอนดังนี้
...
var _questions = [
{
'question': 'คุณชอบสีอะไร',
'answer': [
{'text': 'แดง', 'score': 10},
{'text': 'ดำ', 'score': 7},
{'text': 'น้ำเงิน', 'score': 5},
{'text': 'ขาว', 'score': 1},
]
},
{
'question': 'สัตว์เลี้ยงที่ชื่นชอบคือออะไร',
'answer': [
{'text': 'แมว', 'score': 10},
{'text': 'กระต่าย', 'score': 7},
{'text': 'นกแก้ว', 'score': 5},
{'text': 'เสือ', 'score': 1}
]
},
{
'question': 'ชอบอาหารอะไรที่สุด',
'answer': [
{'text': 'ซุบเนื้อ', 'score': 10},
{'text': 'ต้มยำกุ้ง', 'score': 7},
{'text': 'กะเพราไก่', 'score': 5},
{'text': 'ไข่เจียว', 'score': 1}
]
},
{
'question': 'ภาษาคอมที่ชื่นชอบคืออะไร',
'answer': [
{'text': 'dart', 'score': 10},
{'text': 'python', 'score': 7},
{'text': 'c++', 'score': 5},
{'text': 'swift', 'score': 1}
]
}
];
...
...
var _questionId = 0;
var _totalScore = 0;
void _answer(int score) {
_totalScore += score;
if (_questionId == _questions.length) {
_questionId = -1;
_totalScore = 0;
}
setState(() {
_questionId += 1;
});
print(_questionId);
print(_totalScore);
}
...
...
@override
Widget build(BuildContext context) {
//if (_questionId == questions.length) _questionId = 0;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My App Bar'),
),
body: _questionId < _questions.length
? Quiz(
handler: _answer,
questions: _questions,
questionId: _questionId,
)
: Restart(
_questionId,
_answer,
_totalScore,
)),
);
}
...
restart.dart
import 'package:flutter/material.dart';
class Restart extends StatelessWidget {
final Function handler;
final int questionId;
final int totalScore;
Restart(this.questionId, this.handler, this.totalScore);
String get resultText {
String text;
if (totalScore >= 35) {
text = 'Excellent';
} else if (totalScore >= 28) {
text = 'Good';
} else if (totalScore >= 20) {
text = 'OK';
} else {
text = 'Poor';
}
return text;
}
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: Text(
'Done!,\n$questionId questions, Score: $totalScore,
\nYou are $resultText\nClick to restart',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
onPressed: () => handler(0)),
);
}
}
เนื่องจากฟังก์ชัน _answer หรือ handler ต้องมีพารามิเตอร์ตอนเรียกใช้งาน แต่พารามิเตอร์ของ onPressed เป็นฟังก์ชันที่ไม่มีพารามิเตอร์ onPressed: ()=>handler(0),
import 'package:flutter/material.dart';
import './question.dart';
import './answer.dart';
class Quiz extends StatelessWidget {
final List
เราแก้รายการคำตอบจาก list [String] เป็น list [Map]
และปรับพารามิเตอร์ที่ส่งไปยัง Answer() ให้ชนิดตรงกัน
run app ควรจะได้ผลลัพธ์เหมือนเดิม


final: runtime constant value (lock after re-assign at runtime)
const: compile time constant value (always lock)
const x = const ['list'];
const y = ['list'];
x = []; // error
y = []; // error
var z = const ['list'];
z.add('list2'); // error, value const
var z2 = const ['list'];
z2 = ['list2']; // ok, z is var
print(z2);
var a = ['list'];
a.add('list2'); // ok
print(a);
a = []; // ok
print(a);
final String str = 'string';
str = 'string2'; // error

2020. mnet50.com