How can I pass flutter textediting controller value from one stateless widget to another stateless widget - flutter

Here Is the main.dart file:
import 'package:flutter/material.dart';
import 'package:untitled/button.dart';
import 'package:untitled/form.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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[MyForm(), MyButton()],
),
),
);
}
}
Here is form.dart file:
import 'package:flutter/material.dart';
class MyForm extends StatelessWidget {
#override
Widget build(BuildContext context) {
TextEditingController x = TextEditingController();
return Container(
child: Center(
child: TextField(
controller: x,
decoration: InputDecoration(labelText: "Name"),
),
),
);
}
}
Here is button.dart file:
import 'package:flutter/material.dart';
class MyButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: ElevatedButton(
onPressed: () {
//if I press this button the textediting field will show 10
},
child: Text("Pass 10"),
),
),
);
}
}
How can I show data in text editingfield if I press the button in button.dart?
What is the optimal way to do these things?
Should I use statefulwidgets in statelesswidget or statelesswidgets in statefulwidgets?
My thought is to use redux or provider to pass this kind of things. Although I don't know this simple thing need state management system or not.

You need to lift the state up (create your controller in the main and pass it to the children)
// main.dart
class _MyHomePageState extends State<MyHomePage> {
TextEditingController x = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[MyForm(x), MyButton(x)],
),
),
);
}
}
class MyForm extends StatelessWidget {
MyForm(this.x);
final TextEditingController x;
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: TextField(
controller: x,
decoration: InputDecoration(labelText: "Name"),
),
),
);
}
}
class MyButton extends StatelessWidget {
MyButton(this.x);
final TextEditingController x;
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: ElevatedButton(
onPressed: () {
x...
//if I press this button the textediting field will show 10
},
child: Text("Pass 10"),
),
),
);
}
}

Related

Setstate not working when adding a widget to the background? [SOLVED]

The widget I made for the background color is causing a problem.
There is a problem when a child widget is added to the Background Color widget I made. In this case setstate doesn't work.
Setstate not working when adding a widget to the background?
Why is the screen not updating?
Why do you think this is not happening? Where am I doing wrong?
//zemin_rengi.dart
import 'package:flutter/material.dart';
class ZeminRengi extends StatefulWidget {
final Widget childWidget;
const ZeminRengi({required this.childWidget});
#override
State<ZeminRengi> createState() => _ZeminRengiState();
}
class _ZeminRengiState extends State<ZeminRengi> {
Widget? _childWidget;
#override
void initState() {
// TODO: implement initState
super.initState();
_childWidget = widget.childWidget;
}
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.blue, Colors.red]),
),
child: _childWidget,
);
}
}
//main.dart
import 'package:builk/zemin_rengi.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> 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: ZeminRengi(
childWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
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),
),
);
}
}
thanks for help.
enter image description here

How to change scaffold colour randomly on clicking separate file's gesturdetector button

I have made two files... one is main.dart and other is homescreen.dart. Homescreen is for scaffold body which is created separately. Now there is a button in home screen for changing colour of scaffold. How to do this?
The main purpose is to know access scaffold from other stateful widget class file...
main.dart
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(child: Scaffold(body: HomeScreen(),)),
);
}
}
homescreen.dart
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
//My query is to PLACE CODE HERE TO CHANGE SCAFFOLD COLOR ON CLICKING
},
child: Center(
child: Container(
color: Colors.red,
height: 60,
width: 200,
child: Center(child: Text('Change Color',)),
),
),
);
}
}
Try this:
main.dart
import 'package:flutter/material.dart';
import 'home.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Color _color = Colors.white;
void changeColor(){
setState(() {
_color = Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(child: Scaffold(
backgroundColor: _color,
body: HomeScreen(changeColor: changeColor,),)),
);
}
}
home.dart
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
VoidCallback? changeColor;
HomeScreen({Key? key, this.changeColor}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: changeColor,
child: Center(
child: Container(
color: Colors.red,
height: 60,
width: 200,
child: const Center(
child: Text(
'Change Color',
),
),
),
),
);
}
}
You can do it like this :
/// EDIT :
I edit it to get the Color random
import 'dart:math' as math;
class _MyAppState extends State<MyApp> {
Color _newColor = Colors.white; // variable with the color you want to change
final rnd = math.Random(); // random
Color getRandomColor() =>
Color(rnd.nextInt(0xffffffff)); // little function to get the color random
void _changeNewColor() { // function that you are going to send to yout HomeScreen
setState(() {
_newColor = getRandomColor();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: HomeScreen(change: _changeNewColor), // function
backgroundColor: _newColor, // here the variable
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({
Key? key,
this.change,
}) : super(key: key);
final Function()? change; // instance and get the funct
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: change,
child: Center(
child: Container(
color: Colors.red,
height: 60,
width: 200,
child: const Center(
child: Text(
'Change Color',
)),
),
),
);
}
}

How do I call a method from a stateful widget inside of a stateful widget

I am trying to clean up my code and want to place one of my methods from a stateful widget inside of a different class that is also a stateful widget but whenever I try to call the method it does not recognize it unless the class that I am calling it from it a stateless widget. I was wondering what the best way to get around this would be without changing the class?
Here is a simple example of my problem, I am trying to call
exampleStatefulWidget.testWidget() inside of MyHomePage which is a stateful widget.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
ExampleStatefulWidget exampleStatefulWidget = ExampleStatefulWidget();
ExampleStatelessWidget exampleStatelessWidget = ExampleStatelessWidget();
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
exampleStatefulWidget.testWidget(), // Can not call method that is inside of a stateful widget
exampleStatelessWidget.testWidget(); // Will call method but only if inside of a stateless widget
},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class ExampleStatefulWidget extends StatefulWidget {
const ExampleStatefulWidget({Key? key}) : super(key: key);
#override
_ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();
}
class _ExampleStatefulWidgetState extends State<ExampleStatefulWidget> {
MyHomePage myHomePage = MyHomePage();
Widget testWidget() {
return Container(); // Do Something
}
#override
Widget build(BuildContext context) {
return Container();
}
}
class ExampleStatelessWidget extends StatelessWidget {
const ExampleStatelessWidget({ Key? key }) : super(key: key);
Widget testWidget() {
return Container(); // Do Something
}
#override
Widget build(BuildContext context) {
return Container(
);
}
}
ExampleStatefulWidget and _ExampleStatefulWidgetState are different class, you can create instance of _ExampleStatefulWidgetState instead. And use the method.
_ExampleStatefulWidgetState exampleStatefulWidget =
_ExampleStatefulWidgetState();
In this case, uses will be like
_MyHomePageState
class _MyHomePageState extends State<MyHomePage> {
Widget? widgetFromMethod;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (widgetFromMethod != null) widgetFromMethod!,
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
exampleStatelessWidget
.testWidget(); // Will call method but only if inside of a stateless widget
final gotWidget = exampleStatefulWidget.testWidget();
setState(() {
widgetFromMethod = gotWidget;
});
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
_ExampleStatefulWidgetState
class _ExampleStatefulWidgetState extends State<ExampleStatefulWidget> {
MyHomePage myHomePage = MyHomePage();
Widget testWidget() {
return Container(
color: Colors.purple,
width: 100,
height: 100,
child: Text("generated method from statefull"),
); // Do Something
}
#override
Widget build(BuildContext context) {
return Container();
}
}
if _ExampleStatefulWidgetState are on separate file, make it public removing _.
it will be ExampleStatefulWidgetState
Calling a printLog method of SecondWidget (Child) from FirstWidget(Parent)
Note: This is not recommended. Use any state management lib to achive this (flutter_bloc, provider etc)
import 'package:flutter/material.dart';
class FirstWidget extends StatefulWidget {
#override
_FirstWidgetState createState() => _FirstWidgetState();
}
class _FirstWidgetState extends State<FirstWidget> {
final key = GlobalKey<_SecondWidgetState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
alignment: Alignment.center,
child: Column(
children: [
ElevatedButton(
onPressed: () {
key.currentState?.printLog();
},
child: Text("Click"),
),
SecondWidget(key)
],
),
),
),
);
}
}
class SecondWidget extends StatefulWidget {
SecondWidget(Key key) : super(key: key);
#override
_SecondWidgetState createState() => _SecondWidgetState();
}
class _SecondWidgetState extends State<SecondWidget> {
#override
Widget build(BuildContext context) {
return Container(padding: EdgeInsets.all(20), child: Container());
}
void printLog() {
print("I am called");
}
}

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

How to invoke a rebuild of a stateless widget?

Context
I have two stateless widgets (pages): HomePage and DetailsPage. Obviously the application starts and launches the HomePage. There is a button the user can press to navigate to the DetailsPage with a Navigator.pop() button to navigate back to the HomePage.
I know when the DetailsPage is done being used with the .whenComplete() method. It is at this point I want to rebuild the HomePage widget.
Code
This is the minimum reproduction of my behavior.
main.dart
import 'package:example/home.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
home.dart
import 'package:example/details.dart';
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
static const name = 'Home Page';
const HomePage() : super();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
color: Colors.blue,
textColor: Colors.white,
child: Text(name),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: DetailsPage.builder),
).whenComplete(() => print('Rebuild now.'));
},
),
),
);
}
}
details.dart
import 'package:flutter/material.dart';
class DetailsPage extends StatelessWidget {
static const name = 'Details Page';
static WidgetBuilder builder = (BuildContext _) => DetailsPage();
const DetailsPage();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(name),
MaterialButton(
color: Colors.blue,
textColor: Colors.white,
child: Text('Go Back'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
}
}
Question
How can I invoke a rebuild of this stateless widget (HomePage) at the .whenComplete() method callback?
You can force rebuild the widget tree as follows:
class RebuildController {
final GlobalKey rebuildKey = GlobalKey();
void rebuild() {
void rebuild(Element el) {
el.markNeedsBuild();
el.visitChildren(rebuild);
}
(rebuildKey.currentContext as Element).visitChildren(rebuild);
}
}
class RebuildWrapper extends StatelessWidget {
final RebuildController controller;
final Widget child;
const RebuildWrapper({Key? key, required this.controller, required this.child}) : super(key: key);
#override
Widget build(BuildContext context) => Container(
key: controller.rebuildKey,
child: child,
);
}
In your case,
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final RebuildController controller = RebuildController();
MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RebuildWrapper(
controller: controller,
child: HomePage(
rebuildController: controller,
),
),
);
}
}
class HomePage extends StatelessWidget {
static const name = 'Home Page';
final RebuildController rebuildController;
const HomePage({Key? key, required this.rebuildController}) : super(key: key);
#override
Widget build(BuildContext context) {
print('Hello there!');
return Scaffold(
body: Center(
child: MaterialButton(
color: Colors.blue,
textColor: Colors.white,
child: const Text(name),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: DetailsPage.builder),
).whenComplete(rebuildController.rebuild);
},
),
),
);
}
}
class DetailsPage extends StatelessWidget {
static const name = 'Details Page';
static WidgetBuilder builder = (BuildContext _) => const DetailsPage();
const DetailsPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(name),
MaterialButton(
color: Colors.blue,
textColor: Colors.white,
child: const Text('Go Back'),
onPressed: () => Navigator.pop(context),
),
],
),
),
);
}
}
class RebuildController {
final GlobalKey rebuildKey = GlobalKey();
void rebuild() {
void rebuild(Element el) {
el.markNeedsBuild();
el.visitChildren(rebuild);
}
(rebuildKey.currentContext as Element).visitChildren(rebuild);
}
}
class RebuildWrapper extends StatelessWidget {
final RebuildController controller;
final Widget child;
const RebuildWrapper({Key? key, required this.controller, required this.child}) : super(key: key);
#override
Widget build(BuildContext context) => Container(
key: controller.rebuildKey,
child: child,
);
}
But it is unnatural to force rebuild stateless widgets as they are not supposed to be rebuilt. You should use stateful widget or other state management solutions so that your HomePage will only be updated on meaningful state change.
Source - this answer