Flutter exception caught by widgets library failed assertion - widget

I am getting below exception. I am just learning Flutter.
Below is my code:
import 'package:flutter/material.dart';
void main() => runApp(new FriendlyChatApp());
const String _name = "Hammad Tariq";
class FriendlyChatApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: "Friendly Chat",
home: new ChatScreen(),
);
}
}
class ChatScreen extends StatelessWidget {
ChatScreen({this.text});
final String text;
#override
Widget build(BuildContext context) {
return new Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 10.0),
child: new CircleAvatar(
child: new Text(_name),
),
),
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(_name, style: Theme.of(context).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text),
),
],
)
],
),
);
/*return new Scaffold(
appBar: AppBar(
title: new Text("Chat App"),
),
);*/
}
}

The issue is in the line
child: new Text(text)
where String text is null.
You've defined text as an optional parameter and you are not passing it from FriendlyChatApp.
If you require some inputs from parent page for the child to work properly then you can define it with #required annotation because you won't miss it accidentally.

Related

How to send json data from on route to another route

In my Flutter application, I am trying to pass JSON data from one route to another. The challenge I am facing is how to pass a list as a parameter. The first screen contains a list of JSON data that has been fetched, and I aim to show the complete details of each item when the user clicks on the respective ListTile.
you will find the onTap() in JsonParsingPodo.dart
here's my code :
posts.dart (plain old dart object file)
class PostList {
final List<Post> posts;
PostList({required this.posts});
factory PostList.fromJson(Map<String, dynamic> parsedJson) {
List<dynamic> postsJson = parsedJson['posts'] as List;
List<Post> posts = <Post>[];
posts = postsJson.map((e) => Post.fromJson(e)).toList();
return PostList(posts: posts);
}
}
class Post {
int userId;
int id;
String title;
String body;
Post(
{required this.id,
required this.body,
required this.title,
required this.userId});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
body: json['body'],
title: json['title'],
userId: json['userId']);
}
}
JsonParsingPodo.dart (First Screen)
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:podo_practice/posts.dart';
import 'display.dart';
class JsonParsingPodo extends StatefulWidget {
const JsonParsingPodo({super.key});
#override
State<JsonParsingPodo> createState() => _JsonParsingPodoState();
}
class _JsonParsingPodoState extends State<JsonParsingPodo> {
late Future<PostList> data;
#override
void initState() {
super.initState();
Network network = Network("https://dummyjson.com/posts");
data = network.loadPost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("PODO: json"),
),
body: Center(
// ignore: avoid_unnecessary_containers
child: Container(
child: FutureBuilder(
future: data,
builder: (context, AsyncSnapshot<PostList> snapshot) {
List<Post> allposts;
if (snapshot.hasData) {
allposts = snapshot.data!.posts;
return createListView(allposts, context);
}
return const CircularProgressIndicator();
}),
),
));
}
Widget createListView(List<Post> data, BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Divider(
height: 5.0,
),
ListTile(
title: Text("${data[index].title}"),
subtitle: Text("${data[index].body}"),
leading: Column(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.green,
radius: 23,
child: Text("${data[index].id}"),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DisplayData()),
// *what to pass here??*
);
},
),
],
);
});
}
}
class Network {
final String url;
Network(this.url);
Future<PostList> loadPost() async {
final response = await get(Uri.parse(Uri.encodeFull(url)));
if (response.statusCode == 200) {
//ok
return PostList.fromJson(json.decode(response.body));
} else {
throw Exception("Failed to load data. ");
}
}
}
DisplayData.dart (Second Screen)
import 'package:flutter/material.dart';
import 'package:podo_practice/posts.dart';
class DisplayData extends StatefulWidget {
const DisplayData({super.key});
#override
State<DisplayData> createState() => _DisplayDataState();
}
class _DisplayDataState extends State<DisplayData> {
late Future<PostList> data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Display Post"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: [
// Text(data);
],
),
),
),
);
}
}
I have recently started learning Flutter and don't have much knowledge. I tried reading articles on Stack Overflow about this thing, but I didn't understand much. So, I have decided to post a question for help. Please assist me in completing the following code.
On the "Display Data" page, I need to display the **title **and its **description **when the user clicks on the ListItem.
onListile tap send particular object using index
Widget createListView(List<Post> data, BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
Post post = data[index]
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Divider(
height: 5.0,
),
ListTile(
title: Text("${data[index].title}"),
subtitle: Text("${data[index].body}"),
leading: Column(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.green,
radius: 23,
child: Text("${data[index].id}"),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DisplayData(post:post)),
// *what to pass here??*
);
},
),
],
);
});
}
}
get post on constructor to display
import 'package:flutter/material.dart';
import 'package:podo_practice/posts.dart';
class DisplayData extends StatefulWidget {
final Post post;
const DisplayData({super.key,required this.post});
#override
State<DisplayData> createState() => _DisplayDataState();
}
class _DisplayDataState extends State<DisplayData> {
late Future<PostList> data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Display Post"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: [
// Text(data);
],
),
),
),
);
}
}

How to modify Function in flutter?

code:
class MenuWidget extends StatelessWidget {
final Function(String) onItemClick;
const MenuWidget({Key key, this.onItemClick}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
sliderItem('Home', Icons.home,context),
sliderItem('Setting', Icons.settings,context),
sliderItem('LogOut', Icons.arrow_back_ios,context)
],
),
);
}
Widget sliderItem(String title, IconData icons) => ListTile(
title: Text(title,),
leading: Icon(icons),
onTap: () {
onItemClick(title);
});
}
The variable title will show the clicked item's name,such as "LogOut" or "Setting",I want to modify onItemClick to navigate to different pages,like router.navigateTo(context, '/welcome'),but I dont know how to use onItemClick,Thanks!!!
Method 1
return Container(
child: Column(
children: <Widget>[
sliderItem('Home', Icons.home,context,(){
//todo
router.navigateTo(context, '/welcome');
}),
//Other items...
],
),
);
Widget sliderItem(String title, IconData icons, VoidCallback onClicked) => ListTile(
title: Text(title,),
leading: Icon(icons),
onTap: onClicked
);
Method 2 (As you are using named routes !
return Container(
child: Column(
children: <Widget>[
sliderItem('Home', Icons.home,'welcome'),
//Other items...
],
),
);
Widget sliderItem(String title, IconData icons, String route) => ListTile(
title: Text(title,),
leading: Icon(icons),
onTap: (){
router.navigateTo(context, '/' + route);
}
);

how to inject function to other class in flutter

I want to print 'test' when clicking MyButton
I made constructs with a function in my class but didn't work
please help me
here is my code
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'bla bla bla',
),
MyButton((){print('test');}, 'my button')
],
),
I'm made a StatefulWidget class I called it MyButton
import 'package:flutter/material.dart';
class MyButton extends StatefulWidget {
Function buttonFunction;
String buttonName;
MyButton(this.buttonFunction,this.buttonName);
#override
_MyButtonState createState() => _MyButtonState();
}
class _MyButtonState extends State<MyButton> {
#override
Widget build(BuildContext context) {
String name=widget.buttonName;
return Container(
width: 200,
child: RaisedButton(
color: Colors.red,
onPressed: () {
widget.buttonFunction;
print('clicked $name');
},
textColor: Colors.white,
child: Text("$name",
style: TextStyle(fontSize: 18,),
),
),
);
}
}
You are missing the parenthesis "()" to call the function, instead you are just referencing it.
You are also setting a variable inside the build method which is the wrong place to declare variables, as it will re-run many times and be re-declared unnecessarily and become expensive. If you want to access the property of a value inside a String you just have to use `"String ${widget.myStringVariable}.".
I've modified your code to reflect these changes:
class _MyButtonState extends State<MyButton> {
#override
Widget build(BuildContext context) {
return Container(
width: 200,
child: RaisedButton(
color: Colors.red,
onPressed: () {
widget.buttonFunction();
print('clicked $name');
},
textColor: Colors.white,
child: Text("${widget.buttonName}",
style: TextStyle(fontSize: 18,),
),
),
);
}
}

How can I pass a buttonClick to a Function on another Page?

I'm trying to pass a simple buttonpress to performe something in another class. The point is to use one page for several different functions, instead of having one page for every function.
Right now the navigation to the textDeclaration-page works fine, but I can't get the right function do do its job.
If I press the First Button, the info from FirstButton Widget should display on the textDeclaration page, and if I press the Second Button, the info from SecondButton Widget should pop up on the displayText-page.
Main:
import 'package:flutter/material.dart';
import 'homePage.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
HomePage:
import 'package:flutter/material.dart';
import 'textDeclaration.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Function buttonChoice;
Widget outlineButton(String buttonName) {
return SizedBox(
height: 60.0,
width: 225.0,
child: OutlineButton(
highlightedBorderColor: Colors.lightBlueAccent,
child: Text(buttonName,
style: TextStyle(fontSize: 17.0, fontWeight:
FontWeight.bold)),
borderSide: BorderSide(
color: Colors.blue,
width: 2.0,
),
onPressed: () {
navigate(buttonName, buttonChoice);
}),
);
}
void navigate(String buttonName, Function buttonChoice) {
setState(() {
Navigator.of(context).popUntil(ModalRoute.withName('/'));
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => TextDeclaration(
buttonName: buttonName,
buttonChoice: buttonChoice,
)));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('HOME PAGE')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
outlineButton('First Button'),
outlineButton('Second Button'),
],
),
),
);
}
}
textDeclarationPage:
import 'package:flutter/material.dart';
class TextDeclaration extends StatefulWidget {
final String buttonName;
final Function buttonChoice;
TextDeclaration({this.buttonName, this.buttonChoice});
#override
_TextDeclarationState createState() => _TextDeclarationState();
}
class _TextDeclarationState extends State<TextDeclaration> {
String buttonName = "";
buttonChoice(String buttonName) {
if (buttonName == 'First Button') {
firstButton(buttonName);
} else if (buttonName == 'Second Button') {
secondButton(buttonName);
}
}
Widget firstButton(buttonName) {
return Scaffold(
appBar: AppBar(
title: Text('First Button'),
),
body: Center(
child: Container(
height: 200.0,
width: 200.0,
child: Center(child: Text('First Button Text')),
),
),
);
}
Widget secondButton(buttonName) {
return Scaffold(
appBar: AppBar(
title: Text('Second Button'),
),
body: Center(
child: SizedBox(
height: 200.0,
width: 200.0,
child: Center(
child: Text('Second Button Text'),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.blue),
child: buttonChoice(buttonName),
);
}
}
The code runs, but the functions from the different buttons won't work.
Any help at all would be great since I've been stuck with this for a very long time now. Thanks.

issues with input length and buttonclicks

I'm working on a simple math-app for my daughter. Below is some code that you can use if you like (it may not be the most beautiful code, but it works ok and maybe it helps someone).
My issues are:
1) To limit the number of characters (numbers) that the user can type. I only find solutions about this when it comes to textFields (such as maxLength).
2) My refresh-button ("NEXT") is not working at all. The idea is to give the user a new random math-task from the previous arithmetic choice.
3) Currently you can type the wrong answer, click ok and then correct your answer to get a "Correct". The plan is that once you've clicked ok, you won't be able to change your answer. You will only be able to click NEXT. (I plan to implement a counter to this later, that will return the number of correct and false answers after x numbers of tasks).
Any help is highly appreciated (code or what I shall look at). Thank you.
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'),
],
),
],
),
],
),
);
}
}
Well It's working. It's not the best way to do this but I tried keep your old code base.I really advise make use of some patterns like BLoC to manage the state of the widgets and avoid setState calls.
Was needed split your code in some more classes.
What I have done here??
Create a enum called MathOperation. This enum is used to identify what kind of arithmetic operation the user selected.
The older FirstClass is now OperationSelectorScreen
The older SecondClass is now QuestionAndAnswerScreen
I've created CustomTextField class to implement a simple 'text field' with a max number of characters.
I've implmented MathOperationTask class. This class is an abstraction for arithmetics operations like sum and subtraction. This class holds the numbers involved in operation, his symbol "+" or "-" and the operation results.
There is some comments in source code to guide you, if you need to ask for something feel free to do I will answer when I can. I hope it helps.
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),
),
),
),
);
}
}