Flutter: Access function in another class/file - flutter

In the following set-up, how would I allow fileb.dart to access the function reset that is in filea.dart:
filea.dart:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test',
theme: ThemeData(
primaryColor: Colors.pink[200],
),
home: MyHomePage(title: ''),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage>
{
int testCount = 0;
void test() {
setState(() {
testCount++;
});
}
fileb.dart
import 'package:flutter/material.dart';
import './filea.dart';
class Buttons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 11.0, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FloatingActionButton(
heroTag: "btn1",
onPressed: () => MyHomePageState.test(),
child: const Icon(Icons.cancel),
splashColor: Colors.pink[900],
backgroundColor: Colors.pink[200],
),
),
],
),
),
],
);
}
}
What do I need to change to make this work?

You cannot call a function in another class unless it is static, and it should not deal with any variables that are non-static/local or it will through an error.
Another way to call a function is to pass it as an argument to the page.

You can achieve this through function callback.
Pass the test callback to ButtonWifget's constructor and use the callback in fab button onPressed as below mentioned sample code:
// In Button class
Buttons({this.testCallback});
final Function testCallback;
...
FloatingActionButton(
heroTag: "btn1",
onPressed: testCallback,
)
// In MyHomePage class, pass the callback wherever you have used `Buttons` widget
Buttons(testCallback:test());
Hope this helps you :)

Related

How can I add multiple void methods to a class in Flutter ? (Missing concrete implementation of 'State.build'.)

I'm a beginner in Flutter, I'm building a counter app and I wanted to add the functionalities of "On Clear" and "Decrease" not only increase the counter on click. I thought it'd be logical to add another two methods inside the class MyHomePage but it gives me the error of
Missing concrete implementation of 'State.build'.
I work another way around my code but what if I want to call a method inside that class that does that?
Here's my code
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Hello Code Palace",
theme: ThemeData(primarySwatch: Colors.deepPurple),
home: MyHomePage(title: "Hello app!"));
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
++_counter;
});
/*void _decreaseCounter() {
setState(() {
--_counter;
});*/
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("The button has been pressed"),
Text(
" $_counter times",
style: new TextStyle(fontSize: 30.0),
)
],
),
),
floatingActionButton: Stack(children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 30.0, bottom: 24.0),
child: FloatingActionButton(
onPressed: ()=>setState(()=> --_counter),
tooltip: "Decrease",
child: Icon(Icons.remove),
),
),
Padding(
padding: const EdgeInsets.only(left: 265.0, bottom: 24.0),
child: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: "Increase",
child: Icon(Icons.add),
),
),
Padding(
padding: const EdgeInsets.only(left: 130.0, bottom: 24.0),
child: FloatingActionButton(
onPressed: ()=>setState(()=> _counter = 0),
tooltip: "Increase",
child: Icon(Icons.clear_all),
),
),
]),
);
}
}
If you see a way to arrange the buttons at the bottom in a more organized way I'd appreciate that as well.
You should add new function outside of _incrementCounter().
Please check the below code :
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
++_counter;
});
}
void _decreaseCounter() {
setState(() {
--_counter;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
...
);
}
}

Error Missing concrete implementation of 'StatefulWidget.createState'. Try implementing the missing method, or make the class abstract

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("asset/image/Bestone.jpg")))));
}
}
No matter what I'm using, I have a problem when I'm trying to run or code. I get this error.
Missing concrete implementation of 'StatefulWidget.createState'. Try implementing the missing method, or make the class abstract for the MyApp ()
StatefulWidget requires override method createState So you must override that method. Remove the build method and specify the following line inside MyApp
#override
_MyHomePageState createState() => _MyHomePageState();
Full example with proper StateFulWidget
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

Updating a widget and issue with setStat

I am currently working on this tutorial in which transfers a variable "myVariable" an external file to another.
Link:
https://dev.to/lucianojung/global-variable-access-in-flutter-3ijm
I modified my code so that the variable "myVariable" is usable in the myservice.dart file, it works, but the problem is that I cannot dynamically update my text widget "widget.myVariable", it updates only when I do a "hot reaload" I think we should add a setStat, but I do not know how to implement it despite several attempts.
Thanks for your help
myservice.dart
import 'package:flutter/material.dart';
import 'main.dart';
class MyService extends StatefulWidget {
//Passed 'myVariable' ///////////////////////////////////////////////////
static final MyService _instance = MyService._internal();
// passes the instantiation to the _instance object
factory MyService() => _instance;
//initialize variables in here
MyService._internal() {
_myVariable = 0;
}
int _myVariable;
//short getter for my variable
int get myVariable => _myVariable;
//short setter for my variable
set myVariable(int value) => myVariable = value;
void incrementMyVariable() => _myVariable++;
/////////////////////////////////////////////////////
#override
_MyServiceState createState() => _MyServiceState();
}
class _MyServiceState extends State<MyService> {
/* i try this but no result
_displayCounter() {
setState(() {
widget.myVariable;
});
}
*/
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
width: 250,
height: 90,
child: Text(
// '${_displayCounter()}',
'${widget.myVariable}',
),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'myservice.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Service Demo App'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
MyService _myService = MyService();
_incrementCounter() {
setState(() {
_myService.incrementMyVariable();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
MyService(), //myservice.dart
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
We use a singleton when we need to manage a shared resource.
You can read more here.
What you are trying here, is to use the singleton class as a 'widget'.
It is evident that you are trying to use myVariable. Perhaps you can make a separate widget that meets this requirement.
1 -> Edit main.dart : I will make use of _myService object and pass it to Service() where it is supposed to show the count.
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
/* Now because of setState(), the build method will be called
as many times as the counter increases, which will call
Service() with the MyService instance below
*/
Service(_myService), // ------ service_widget.dart
]
2 -> Leave myservice.dart as it is (as given in the tutorial).
3 -> service_widget.dart will be as follows:
import 'package:flutter/material.dart';
import './myservice.dart';
class Service extends StatelessWidget {
final MyService myService;
Service(this.myService); // making use of MyService instance
#override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
width: double.infinity,
child: Text(
'${myService.myVariable}', // Access myVariable here
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
);
}
}
Now it works fine!
Though you can see the full code here, I highly recommend you play around some more.
main.dart
myservice.dart
service_widget.dart

How to pass variables between 2 different files and manipulate them

I am learning flutter, and I would like to know how to pass a variable or a method between 2 different files (to add additional widgets).
In my example, I took the code provided by flutter when we create a new project, to this code, I added a second file called "second.dart" in which I get the variable "_counter" in the file main "main.dart" which I multiply by 10.
main.dart
import 'package:flutter/material.dart';
import 'second.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Container(
child: Second(),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
second.dart
import 'package:flutter/material.dart';
import 'main.dart';
class Second extends StatefulWidget {
#override
_SecondState createState() => _SecondState();
}
class _SecondState extends State<Second> {
int counter10 = _MyHomePageState._counter * 10;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
width: 200,
height: 300,
child: Text('My increment * 10 : $counter10 '),
);
}
}
however, I have this error."_MyHomePageState" is highlighted in red.
lib/second.dart:11:18: Error: Getter not found: '_MyHomePageState'.
var counter10 =_MyHomePageState._counter * 10;
Thank you for your help
See this isn't the way how we pass variables to the other files or other widgets. To create a widget you need to choose between stateful or stateless if you want to manipulate state from inside of the Second class declare it as a stateful but in your case you need to have a stateless widget.
For Example this:
class Second extends StatelessWidget {
final int counter;
const Second({Key key, this.counter}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
width: 200,
height: 300,
child: Text('My increment * 10 : ${counter * 10} '));
}
}
And Pass this variable from your first that is like this :
import 'package:flutter/material.dart';
import 'second.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Container(
child: Second(counter:_counter),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Note : You can share normal variables by referring them across classes but they shouldn't be private eg have an _ in front of them. Another thing even if you share your variable it wont have any effect on the Second Page directly as flutter doesn't know that it is changing and rather just treat it as an instance.
You can share static data using classes:
example
class AppStrings {
static Color appColor = Colors.blue;
}
And later refer to it as AppStrings.appColor
There are some points that you should do in your codes:
when we use underscore as the first character of the variable name, it means that this variable is private! so you can not use int counter10 = _MyHomePageState._counter * 10; in the second widget!
if you want to pass variables to the child widget, you need to create a constructor as follow:
class Second extends StatefulWidget {
int counter;
Second(this.counter);
#override
_SecondState createState() => _SecondState();
}
now you can pass _countre variable to the Second widget:
Container(
child: Second(_counter),
),
please let me know if there is any problem or error.

calling setState from drawer?

Context
Using the standard flutter demo I added a drawer. I put the contents of my drawer in another class in another file. Both are stateful widgets. I use a floating action button in the drawer with setState incrementing the global variable for the number shown on the main screen.
What happens
When I press it nothing happens.
It does not update the text on the main page/main.dart until I use the floating action button on the main page/main.dart. Then it adds all the increments I added in the drawer too.
So it's just not rebuilding the widget.
How do I get it to rebuild the widget? I thought everything you needed was that they were both inside a setstate?
Best possible cause I have come up with
Is it because even though I use a stateful widget inside a stateful widget, the setstate only works on the embedded stateful widget because the embedded widget is technically a created object in the main.dart?
Code for main.dart
import 'package:flutter/material.dart';
import 'drawer.dart';
DrawerClass _drawer = DrawerClass();
int counter = 0;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _incrementCounter() {
setState(() {
counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
endDrawer: SafeArea(child: Drawer(child: Container(child: _drawer,),)),
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Code for drawer
import 'package:flutter/material.dart';
import 'main.dart';
class DrawerClass extends StatefulWidget {
#override
_DrawerClassState createState() => _DrawerClassState();
}
class _DrawerClassState extends State<DrawerClass> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF222831),
body: Container(
width: 100,
child: Center(
child: FloatingActionButton(
tooltip: 'Increment',
child: Icon(Icons.add),
onPressed: () {
setState(() {
counter++;
});
},
),
),
),
);
}
}
Just pass the _incrementCounter to the DrawerClass. With this change your DrawerClass can now be a StatelessWidget and there will be no need for the counter and _drawer variables to be global. Please see the code below :
main.dart
import 'package:flutter/material.dart';
import 'drawer.dart';
//DrawerClass _drawer = DrawerClass();
//int counter = 0;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int counter = 0;
void _incrementCounter() {
setState(() {
counter++;
});
}
#override
Widget build(BuildContext context) {
final DrawerClass _drawer = DrawerClass(
increment: _incrementCounter,
);
return Scaffold(
endDrawer: SafeArea(
child: Drawer(
child: Container(
child: _drawer,
),
)),
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
drawer.dart
import 'package:flutter/material.dart';
class DrawerClass extends StatelessWidget {
final Function increment;
const DrawerClass({Key key, this.increment}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF222831),
body: Container(
width: 100,
child: Center(
child: FloatingActionButton(
tooltip: 'Increment',
child: Icon(Icons.add),
onPressed: increment,
),
),
),
);
}
}