我正在为我的女儿开发一个简单的数学应用程序。以下是一些您可以使用的代码(它可能不是最漂亮的代码,但是它可以正常工作,也许可以对某人有所帮助)。
我的问题是:
1)限制用户可以输入的字符数(数字)。我只有在涉及到textFields(例如maxLength)时才找到解决方案。
2)我的刷新按钮(“ NEXT”)根本不起作用。这个想法是给用户一个新的随机数学任务,它来自先前的算术选择。
3)当前,您可以输入错误的答案,单击“确定”,然后更正您的答案以获得“更正”。计划是,一旦单击“确定”,您将无法更改答案。您将只能单击“下一步”。 (我计划稍后再实现一个计数器,该计数器将在x个任务后返回正确和错误答案的数目。)
任何帮助(代码或我将要看到的内容)都受到高度赞赏。谢谢。
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) => runApp(HomePage()));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'input',
theme: ThemeData(primarySwatch: Colors.purple),
home: FirstClass(),
);
}
}
class FirstClass extends StatefulWidget {
@override
_FirstClassState createState() => _FirstClassState();
}
class _FirstClassState extends State<FirstClass> {
final random = Random();
int a, b, c, sum;
String output;
void changeData(String buttonName) {
setState(() {
a = random.nextInt(10);
b = random.nextInt(10);
if (buttonName == '+') {
sum = a + b;
output = '$a+$b= ';
} else if (buttonName == '-') {
if (a >= b) {
sum = a - b;
output = '$a-$b= ';
} else if (b > a) {
sum = b - a;
output = '$b-$a= ';
}
}
print(sum.toString());
Navigator.of(context).popUntil(ModalRoute.withName('/'));
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SecondClass(
sum: sum,
refresh: changeData,
output: output,
buttonName: buttonName,
)));
});
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.deepPurple),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0.0,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
title: Text(
'MATH',
style: TextStyle(fontSize: 25.0),
),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
child: Text('+', style: TextStyle(fontSize: 24.0)),
onPressed: () => changeData('+')),
RaisedButton(
child: Text('-', style: TextStyle(fontSize: 24.0)),
onPressed: () => changeData('-')),
],
),
),
),
);
}
}
class SecondClass extends StatefulWidget {
final int sum;
final String output;
final String buttonName;
final Function refresh;
SecondClass({this.sum, this.refresh, this.buttonName, this.output});
@override
_SecondClassState createState() => _SecondClassState();
}
class _SecondClassState extends State<SecondClass> {
String output = "";
String _output = "";
String output2 = "";
@override
void initState() {
super.initState();
}
buttonPressed(String buttonText) {
if (buttonText == "<-") {
_output = "";
} else if (buttonText == "OK") {
if (output.isNotEmpty) {
if (output == widget.sum.toString()) {
setState(() {
output2 = 'Correct';
});
} else {
setState(() {
output2 = 'False';
});
}
} else if (buttonText == "NEXT") {
widget.refresh(widget.buttonName);
}
} else {
_output = _output + buttonText;
}
setState(() {
output = _output;
});
print(buttonText);
}
Widget buildButton(String buttonText) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 8.0),
child: OutlineButton(
color: Colors.white,
child: Text(
buttonText,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
onPressed: () => buttonPressed(buttonText)),
),
);
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.purple),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 40.0, left: 20.0, right:
20.0),
child: Container(
height: 60.0,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15.0)),
child: Center(
child: Text(
widget.output + output,
style: TextStyle(
color: Colors.black,
fontSize: 48.0,
fontWeight: FontWeight.bold),
),
)),
),
Padding(
padding: const EdgeInsets.only(top: 20.0, left: 20.0, right:
20.0),
child: Container(
height: 60.0,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15.0)),
child: Text(
output2,
style: TextStyle(
color: Colors.black,
fontSize: 48.0,
fontWeight: FontWeight.bold),
),
),
),
Expanded(child: Divider()),
Column(
children: <Widget>[
Row(
children: <Widget>[
buildButton('1'),
buildButton('2'),
buildButton('3'),
],
),
Row(
children: <Widget>[
buildButton('4'),
buildButton('5'),
buildButton('6'),
],
),
Row(
children: <Widget>[
buildButton('7'),
buildButton('8'),
buildButton('9'),
],
),
Row(
children: <Widget>[
buildButton('<-'),
buildButton('0'),
buildButton('OK'),
],
),
Row(
children: <Widget>[
buildButton('NEXT'),
],
),
],
),
],
),
);
}
}
答案 0 :(得分:1)
嗯,它正在工作。这不是最好的方法,但我尝试保留您的旧代码库。我真的建议您使用BLoC之类的模式来管理小部件的状态并避免setState调用。
根据需要将您的代码分成更多的类。 我在这里做了什么?
创建一个名为MathOperation
的枚举。该枚举用于识别用户选择了哪种算术运算。
旧的FirstClass现在是OperationSelectorScreen
旧的SecondClass现在是QuestionAndAnswerScreen
我创建了CustomTextField
类来实现一个具有最多字符数的简单“文本字段”。
我实施了MathOperationTask
类。此类是诸如加法和减法之类的算术运算的抽象。此类包含与操作有关的数字,其符号“ +”或“-”以及操作结果。
源代码中有一些注释可以指导您,如果您需要随意做的事情,我会在可能的情况下回答。希望对您有所帮助。
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// enum used to identify math operation types
enum MathOperation { SUM, SUBTRACTION }
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) => runApp(HomePage()));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'input',
theme: ThemeData(primarySwatch: Colors.purple),
home: OperationSelectorScreen(),
);
}
}
/// old FirstClass
class OperationSelectorScreen extends StatefulWidget {
@override
_OperationSelectorScreenState createState() => _OperationSelectorScreenState();
}
class _OperationSelectorScreenState extends State<OperationSelectorScreen> {
MathOperation _userSelectedOperation;
void changeData(String buttonName) {
setState(() {
if (buttonName == '+') {
_userSelectedOperation = MathOperation.SUM;
} else if (buttonName == '-') {
_userSelectedOperation = MathOperation.SUBTRACTION;
}
Navigator.of(context).popUntil(ModalRoute.withName('/'));
/// we only need pass to next screen what kind of operation
/// was selected by user
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => QuestionAndAnswerScreen(
operationType: _userSelectedOperation,// operation selected by user ( '+' or '-' )
)));
});
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.deepPurple),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0.0,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
title: Text(
'MATH',
style: TextStyle(fontSize: 25.0),
),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
child: Text('+', style: TextStyle(fontSize: 24.0)),
onPressed: () => changeData('+')),
RaisedButton(
child: Text('-', style: TextStyle(fontSize: 24.0)),
onPressed: () => changeData('-')),
],
),
),
),
);
}
}
/// old SecondClass
class QuestionAndAnswerScreen extends StatefulWidget {
final operationType; // if the operations will be (+) or (-)
QuestionAndAnswerScreen({this.operationType});
@override
_QuestionAndAnswerScreenState createState() => _QuestionAndAnswerScreenState();
}
class _QuestionAndAnswerScreenState extends State<QuestionAndAnswerScreen> {
String _userTypedAnswer=""; // numbers that user had typed
String _answerValidationOutput = ""; // will say if the user answer ir correct or wrong(false)
MathOperationTask _currentTask; // current arithmetic operation
// this member controls the back button "<-" activity
// if user had responded the question, this value will be true and
// the button "<-" will not work properly.
bool _isQuestionResponded = false;
@override
void initState() {
super.initState();
//using math operation task generator method to create a new math operation
_currentTask = MathOperationTask.generateMathTask( widget.operationType );
}
buttonPressed(String buttonText) {
// this logic can be improved if we
// transform the custom keyboard in a widget
if (buttonText == "<-") {
if (!_isQuestionResponded){
_changeUserTypedText("");
_changeAnswerValidationText("");
}
}
else if (buttonText == "OK") {
if (_userTypedAnswer.isNotEmpty) {
_isQuestionResponded = true;
if (_userTypedAnswer == _currentTask.results.toString()) {
_changeAnswerValidationText('Correct');
}
else {
_changeAnswerValidationText('False');
}
}
}
else if (buttonText == "NEXT") {
print("new OP");
_spawnArithmeticOperation();
}
else {
///This if statement solves the problem of put in member after question
///responded.If question is NOT responded, OK button not pressed then we update the text.
if (!_isQuestionResponded)
_changeUserTypedText( (_userTypedAnswer + buttonText) );
}
}
/// this mehtod creates a new arithmetic operation and update the screen with
void _spawnArithmeticOperation(){
_currentTask = MathOperationTask.generateMathTask(widget.operationType);
_answerValidationOutput ="";
_userTypedAnswer = "";
_isQuestionResponded = false;
setState(() {});
}
/// method to change and update UI after user type something.
void _changeUserTypedText(String text){
setState(() => _userTypedAnswer = text );
}
/// update the text if the answer is correct, wrong or clean the text.
void _changeAnswerValidationText(String text){
setState(() => _answerValidationOutput = text );
}
Widget buildButton(String buttonText) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0, bottom: 8.0),
child: OutlineButton(
color: Colors.white,
child: Text(
buttonText,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
onPressed: () => buttonPressed(buttonText)),
),
);
}
@override
Widget build(BuildContext context) {
final operationField = CustomTextField( maxLength: 7, // max text length
text: "${_currentTask.firstMember}" // first member of operation
"${_currentTask.operationSymbol}" // operation signal
"${_currentTask.secondMember}= " // second member of math operation
"$_userTypedAnswer",
);
final answerFinalResultsField = CustomTextField(
maxLength: 7,
text: _answerValidationOutput
);
return Container(
decoration: BoxDecoration(color: Colors.purple),
child: Column(
children: <Widget>[
operationField,
answerFinalResultsField,
Expanded(child: Divider()),
_buildKeyboard(),
],
),
);
}
// here i put your keyboard layout..
Widget _buildKeyboard(){
return Column(
children: <Widget>[
Row(
children: <Widget>[
buildButton('1'),
buildButton('2'),
buildButton('3'),
],
),
Row(
children: <Widget>[
buildButton('4'),
buildButton('5'),
buildButton('6'),
],
),
Row(
children: <Widget>[
buildButton('7'),
buildButton('8'),
buildButton('9'),
],
),
Row(
children: <Widget>[
buildButton('<-'),
buildButton('0'),
buildButton('OK'),
],
),
Row(
children: <Widget>[
buildButton('NEXT'),
],
),
],
);
}
}
/// this class represents an arithmetic operation
/// example 3 + 6 = 9
/// 3 is the firstMember, 6 the secondMember and results is 9.
class MathOperationTask {
final firstMember;
final secondMember;
final results; //operation results
final operationSymbol;
// text math symbols constants only to show...
static final String PLUS = "+";
static final String LESS = "-";
MathOperationTask( {this.firstMember, this.secondMember, this.results, this.operationSymbol} );
/// this method is used to generate a specific math task from a specific type.
static MathOperationTask generateMathTask( MathOperation type ){
var random = Random();
var firstMember = random.nextInt(10);// 0..9
var secondMember = random.nextInt(10);
switch(type){
case MathOperation.SUM:
return MathOperationTask(
firstMember: firstMember,
secondMember: secondMember,
results: (firstMember + secondMember),
operationSymbol: PLUS
);
case MathOperation.SUBTRACTION:
var results;
if (firstMember < secondMember) {
// we exchange the values position in operation...
var temp = firstMember;
firstMember = secondMember;
secondMember = temp;
}
results = firstMember - secondMember;
return MathOperationTask(
results: results,
secondMember: secondMember,
firstMember: firstMember,
operationSymbol: LESS,
);
default:
break;
}
//in case of invalid operation...
return MathOperationTask(
firstMember: 0,
secondMember: 0,
results: 0,
);
}
}
/// A simple custom text field that limits his text
/// with a specific characters number
///
class CustomTextField extends StatelessWidget {
final maxLength;
final _text;
CustomTextField({this.maxLength = 7, String text}) :
_text = (text.length > maxLength) ? text.substring(0, maxLength ) : text;
/// this lines solves characters numbers problem
///if the text contains more characters that is allowed (maxLength) then we
/// cut the string form character 0 until last position allowed (maxLength).
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 40.0, left: 20.0, right: 20.0),
child: Container(
height: 60.0,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15.0)),
child: Center(
child: Text(
_text,
style: TextStyle(
color: Colors.black,
fontSize: 48.0,
fontWeight: FontWeight.bold),
),
),
),
);
}
}