简体   繁体   中英

Flutter Dart OOP programming basics - text from one class to another

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.

在此处输入图像描述

Here are the three code files:

main.dart

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()
          ],
        ),
      ),
    );
  }
}

calculator_button.dart:

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,
                      ))),
            ),
          ),
        );
      }
    }

calculator_button_layout.dart

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,
              ),
            ],
          ),
        ],
      ),
    );
  }
}

MY PROBLEM:


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.

Callbacks

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.


Creating callbacks

  1. Inside calculator_button.dart , add another attribute like so:
final void Function(String) onPressed;
  1. Inside onPressed of the TextButton widget pass it the text value like so:
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


Passing callbacks

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 .

  1. Inside calculator_layout.dart , we'll create a attribute just we did before:
final void Function(String) buttonCallback;
  1. Pass this attribute to each of the button:
CalculatorButton(
    onPressed: buttonCallback,
    ...
),

Declaring callbacks

Finally we're going to provide the body for our callback, this is done inside the parent widget.

  1. Inside main.dart , we want to update the text to the new string so we need to convert our Home widget to stateful widget.

  2. 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
  1. Pass a function to 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
    });
  }
), 
  1. Finally display the text inside our Text widget
child: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM