1.现在要和questions.dart交互,从其中抓取数据并体现出来
位置:questions_screen.dart中
我们先将questions数组的第一个参数赋值给currentQuestion变量,questions[0]也代表了我们要显示第一个答题卡 QuizQuestion('Apple', ['苹果', '梨子', '香蕉', '荔枝'])。
final currentQuestion = questions[0];
我们不希望一个一个地去获取questions中answer的数据,而是利用一个map方法帮助我们统统地遍历出来。
...currentQuestion.answers.map((answer) {
return AnswerButton(answerText: answer, onTap: () {});
})
解释:我用currentQuestion的answer字符串数组,调用了map方法,它会将currentQuestion的answer字符串数组,一个一个地迭代出来并将各自的answer放进作为参数,形成一个一个AnswerButton()并放置进入一个数组中间。但是问题在于AnswerButton()外面也是一个数组,所以形成了数组中的数组,就会报错,所以要在最前面加入...三个点,这三个点会将内层的数组以一个一个的形式剥离出来,安插在外层数组中,最后就没有内层数组了。
例子如下:
const numbers = [1,2,3];
const moreNums = [numbers, 4] == [[1,2,3],4];
const moreNums = [...numbers,4] == [1,2,3,4];
整体修改完的代码如下:
class _QuestionScreenState extends State<QuestionsScreen> {
@override
Widget build(BuildContext context) {
final currentQuestion = questions[0];
return SizedBox(
width: double.infinity, //尽量多地占用空间
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // 使其在y轴上居中
children: [
Text(
currentQuestion.text,
style: const TextStyle(color: Colors.white),
),
const SizedBox(
height: 30,
),
...currentQuestion.answers.map((answer) {
return AnswerButton(answerText: answer, onTap: () {});
}),
],
),
);
}
}
2.稍微调整下排列,填充,边缘
位置:questions_screen.dart中 ---> _QuestionScreenState类中
class _QuestionScreenState extends State<QuestionsScreen> {
@override
Widget build(BuildContext context) {
final currentQuestion = questions[0];
return SizedBox(
width: double.infinity, //尽量多地占用空间
child: Container(
margin: const EdgeInsets.all(40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // 使其在y轴上居中
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
currentQuestion.text,
style: const TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
const SizedBox(
height: 30,
),
...currentQuestion.answers.map((answer) {
return AnswerButton(answerText: answer, onTap: () {});
}),
],
),
),
);
}
}
解释:第(12)行:这行代码的功能就是将x轴的占据拉满
第(8)行:我在Column类外侧包含一个Container类
第(9)行:由于第(12)行代码将x轴占据拉满了,我们需要用margin属性来稍微地缩小点
第(17)行:用于将标题居中。
3.要将答案洗乱掉
数组有个方法叫做shuffle(),它的意思就是洗牌,可以将数组里面的排序洗乱掉。
但是这个shuffle方法会修改原始数组,而不是创建一个新的数组然后再改变它,所以它会污染数据,所以我们要用创建一个副本然后再调用shuffle。
位置:在根目录下,lib --> models --> quiz_question.dart
我们在quiz_question.dart里面再新增一个getShuffledAnswer()的方法,用来创建数组副本并洗乱排序。
class QuizQuestion {
const QuizQuestion(this.text, this.answers);
final String text;
final List<String> answers;
List<String> getShuffledAnswer() {
final shuffledList = List.of(answers);// 复制一个数组
shuffledList.shuffle(); // 洗牌
return shuffledList;
}
}
所以这个方法的返回类型是List<String>;
List.of()方法可以将answer数组复制出一份,并存储在shuffledList中;
紧接着用 shuffledList.shuffle(),我们就成功地让这个副本数组洗乱了。
最后返回这个洗乱了的副本数组。
回到questions_screen.dart中
将原来的迭代显示按钮的代码更换为如下:
...currentQuestion.getShuffledAnswer().map((answer) {
return AnswerButton(answerText: answer, onTap: () {});
}),
用getShuffledAnswer()方法返回一个排序乱了的数组替换了之前的固定排序数组answer。
保存下,刷新后再看看。
所以的确是成功了,我们成功地打乱了数组的排序。
4.选择并点击完答案后,要切入下一个界面
I.答题卡的显示取决于question数组的索引,在这里是0为第一个,这是写死的。接下来既然要让它动态地变化这个就要用变量。
final currentQuestion = questions[0];
II.添加一个currentQuestionIndex变量,并且在每次我们点击答案之后都加1,于是答题卡就跟着变化。
位置:在_QuestionScreenState中:
添加索引变量。
var currentQuestionIndex = 0;
添加答案按钮answerQuestion方法并在每次点击之后索引都加1。
void answerQuestion() {
setState(() {
currentQuestionIndex++;
});
}
修改onTap属性的方法为answerQuestion,注意不要加上(),否则它会自己执行。
...currentQuestion.getShuffledAnswer().map((answer) {
return AnswerButton(answerText: answer, onTap: answerQuestion);
}),
整体代码如下:
class _QuestionScreenState extends State<QuestionsScreen> {
var currentQuestionIndex = 0; //索引变量
void answerQuestion() {
setState(() {
currentQuestionIndex++; //每次按下答案,索引变量都加一
});
}
@override
Widget build(BuildContext context) {
final currentQuestion = questions[currentQuestionIndex]; //将当前的索引变量存储在currentQuestion中
return SizedBox(
width: double.infinity, //尽量多地占用空间
child: Container(
margin: const EdgeInsets.all(40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // 使其在y轴上居中
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
currentQuestion.text,
style: const TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
const SizedBox(
height: 30,
),
...currentQuestion.getShuffledAnswer().map((answer) { //根据索引变量显示不同答题卡
return AnswerButton(answerText: answer, onTap: answerQuestion);
}),
],
),
),
);
}
}
保存下,试下:
整体上成功了,最后会出问题,因为索引过界了,不过之后会处理。
5.再稍微地修改下外观
I.注意到,如果答案长度很长的话,下面哪一行就有些不居中。
位置:在answer_button.dart中 ---> build() ---> child:Text()中
新增一个textAlign属性,赋值TextAlign.center。
child: Text(
answerText,
textAlign: TextAlign.center, //使字体居中
));
保存后,再看下,就居中了。
II.来学习如何导入新字体,并使用它吧
a.首先进入这个链接https://pub.dev/packages/google_fonts
b.点击红框的Installing
c.此为将该字体包安装至本机的步骤;再最上面的终端处,点击新建终端或快捷键ctrl+shift+`
d.在终端处,输入该命令,回车运行。
flutter pub add google_fonts
紧接着,在根目录下的pubspec.yaml文件中,你会发现google_fonts,说明安装成功了,根据时间不同,版本也不同,但没关系。
e.在questions_screen.dart中,将该字体包引入
import 'package:google_fonts/google_fonts.dart';
在 _QuestionScreenState类 ---> build() ---> SizeBox() --> Container() ---> Column() ---> Text()
对Text()内部进行修改如下:
Text(
currentQuestion.text,
style: GoogleFonts.lato(
color: const Color.fromARGB(255, 211, 162, 251),,
fontSize: 24,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
添加一个style属性:并赋值GoogleFonts,即我们刚刚引入的字体包,我们选择lato字体,并且进行了一些参数的修改。
注意:可能你会出现像我这样的问题
解决方法:
在pubspec.yaml文件中,将google_fonts修改为 6.1.0,注意前面不要有^符号,就OK啦
f.既然引入了google字体,那不妨把封面也改下吧:
来到start_screen.dart文件中,找到Text()组件修改为如下:
Text(
'Learn Word the fun way',
style: GoogleFonts.lato( //引入谷歌字体
color: const Color.fromARGB(255, 216, 192, 250),
fontSize: 24),
),
来看下成果吧: