I am extremely new to Flutter. I've followed tons of tutorials..... And now, I am trying to build my own Calculator App . I am having problems with OOP with dart .
I have built the Frontend(UI) for my one-page Calculator app.
import 'package:flutter/material.dart';
import 'calculator_button_layout.dart';
import 'calculator_button.dart';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Magic Calculator"),
elevation: 0.0,
backgroundColor: Colors.grey[900],
centerTitle: true,
),
body: Container(
color: Colors.grey[850],
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Container(
//color: Colors.green,
child: Align(
alignment: Alignment.bottomRight,
child: Text(
"0",
style: TextStyle(
color: Colors.white,
fontSize: 38,
),
),
),
),
),
),
CalculatorButtonLayout()
],
),
),
);
}
}
import 'package:flutter/material.dart';
class CalculatorButton extends StatefulWidget {
final String text;
final Color color;
final int flex;
CalculatorButton({this.text, this.color, this.flex});
@override
_CalculatorButtonState createState() => _CalculatorButtonState();
}
class _CalculatorButtonState extends State<CalculatorButton> {
@override
Widget build(BuildContext context) {
return Expanded(
flex: this.widget.flex,
child: TextButton(
onPressed: () {},
child: Container(
margin: EdgeInsets.all(1),
padding: EdgeInsets.symmetric(
vertical: (MediaQuery.of(context).size.height / 20)),
color: this.widget.color,
child: Center(
child: Text(this.widget.text,
style: TextStyle(
fontSize: 30,
color: Colors.white70,
fontWeight: FontWeight.bold,
))),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'calculator_button.dart';
class CalculatorButtonLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Row(
children: [
CalculatorButton(
text: "C",
color: Colors.red[800],
flex: 1,
),
CalculatorButton(
text: "+/-",
color: Colors.red[800],
flex: 1,
),
CalculatorButton(
text: "%",
color: Colors.red[800],
flex: 1,
),
CalculatorButton(
text: "/",
color: Colors.red[900],
flex: 1,
),
],
),
Row(
children: [
CalculatorButton(
text: "1",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "2",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "3",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "*",
color: Colors.red[900],
flex: 1,
),
],
),
Row(
children: [
CalculatorButton(
text: "4",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "5",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "6",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "+",
color: Colors.red[900],
flex: 1,
),
],
),
Row(
children: [
CalculatorButton(
text: "7",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "8",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "9",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "-",
color: Colors.red[900],
flex: 1,
),
],
),
Row(
children: [
CalculatorButton(
text: "0",
color: Colors.grey[900],
flex: 2,
),
CalculatorButton(
text: ",",
color: Colors.grey[900],
flex: 1,
),
CalculatorButton(
text: "=",
color: Colors.red[900],
flex: 1,
),
],
),
],
),
);
}
}
How can I send the this.widget.text as String to Text() in main.dart as I push the buttons on the calculator! I have looked at all the questions related to "How to get data from one class to the other in flutter" . But have found Navigator.push() being used... But the problem is that My app is a one-pager
There are multiple ways to achieve it. The problem is you have to update the value of Text()
in main.dart
ontap
of calculatorButton
.
Using setState is one of the option. But as your calculatorButton
and Home
are two seprate classes using setState can be complicated to use.
I will use Provider for this data handling.
you can install package from here: https://pub.dev/packages/provider/install
get the package in pubspec.yaml
Providers automatically updates the values of variables without calling build method again and again.
Basically you will create a new class like the following.
class TextValue with ChangeNotifier{
String inputvalue;
get getTextvalue => inputvalue;
void setTextValue(String value){
this.inputvalue = value;
notifyListener();
}
}
notifyListener()
will notify the all the widgets that the value of the variable is changed and you need to rebuild. so every time you will tap on the button and call setTextValue(value)
method it will rebuild the text
widget in main.dart
and value will be updated.
In order to use it you need to Create a provider in your main method. Provider
is like the Superclass that will pass down the data to it's subclasses. So to pass the data in all your app we will wrap MaterialApp
inside the provider
and create a provider
with our TextValue
class. Like this:
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => TextValue(),
child: MaterialApp(
home: Home(),
),
),
);
}
ChangeNotifierProvider
is type of provider which is used to notify on value change. you can find lot's of tutorials on this.
Now how to call this method and get the updated value in the main.dart
.
Lets first check how to call this method:
Caculator_button.dart
Widget build(BuildContext context) {
return Expanded(
flex: this.widget.flex,
child: TextButton(
onPressed: () {
Provider.of<TextValue>(context, listen:false).setTextValue(this.widget.text);
},
This will called the method inside provider. and notify it's childrens.
Now how to use this value.
In Main.dart inside your container
Container(
//color: Colors.green,
child: Align(
alignment: Alignment.bottomRight,
child: Text(
//call the getter using provider
Provider.of<TextValue>(context, listen: false).getTextvalue,
style: TextStyle(
color: Colors.white,
fontSize: 38,
),
),
),
),
That's it. Also further you can Use consumer
widget provided by provider
. You can find out it in documentation.
Although there are many ways to transfer information from one place to other, your usecase is very simple so I'll suggest the simplest solution to you.
You can use the power of callbacks. These are just functions declared in the parent and passed as variables down to the child. The function can be executed from inside the child to manipulate data inside the parent. Your solution would be like this.
final void Function(String) onPressed;
onPressed: (){
widget.onPressed(widget.text);
}
This calls the function provided by the parent, passing it's text value which can then be used inside our parent ie main.dart
Since you've refactored your widgets you'll have to pass the callback down the tree through multiple constructors, which is one of the downsides of not using dependency injection
.
final void Function(String) buttonCallback;
CalculatorButton(
onPressed: buttonCallback,
...
),
Finally we're going to provide the body for our callback, this is done inside the parent widget.
Inside main.dart , we want to update the text to the new string so we need to convert our Home
widget to stateful widget.
Create a variable inside the state to store the text:
class _HomeState extends State<Home> { //<-- Convert to stateful like this
final displayText = "0"; //<-- Add this state variable
CalculatorLayout
:CalculatorLayout(
buttonCallback:(text){ //<-- This is the text that the child(CalculatorButton) passes
setState((){ //<--Rebuilds the home widget to display the updated text
displayText += text; //<-- Joins the new text to the previous one
});
}
),
Text
widgetchild: Text(
displayText,
...
),
You'll see callbacks being used very often by many flutter widgets and are useful when the level is single. But as you can see this can get very messy for bigger apps and a better approach would be using Provider
or GetIt
along with Notifier
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.