How to define variable inside of a text widget located in a separate dart file in Flutter - flutter

I have a messages.dart file that holds all the initial texts for different messages as Widgets.
Widget rest = Text('You should rest $restTime or $restTimeOr');
In the main.dart file, I'm defining the $restTime string value and in the column children, I want to call the rest widget from the messages.dart file.
class _HomePageState extends State<HomePage> {
String restTime = 'now';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
rest,
],
),
);
}
}
But it gives me the error in the messages.dart file that restTime is undefined. What am I missing here?
The complete main.dart file is:
import 'package:flutter/material.dart';
import 'example/messages.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String restTime = 'now';
String restTimeOr = '2 hours later';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
rest,
],
),
);
}
}
And the messages.dart file is:
import 'package:flutter/material.dart';
Widget rest = Text('You should rest $restTime or $restTimeOr');

You can create a RestMessageWidget in your messages.dart like this:
class RestMessageWidget extends StatelessWidget {
final String? restTime;
final String? restTimeOr;
RestMessageWidget({#required this.restTime, #required this.restTimeOr});
#override
Widget build(BuildContext context) {
return Text('You should rest $restTime or $restTimeOr');
}
}
You can then use the RestMessageWidget in main.dart like this:
class _HomePageState extends State<HomePage> {
String myRestTime = 'now';
String myRestTimeOr = '2 hours later';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
RestMessageWidget(restTime: myRestTime, restTimeOr: myRestTimeOr),
],
),
);
}
}

Define the rest message as a statelessWidget rather than a runtime instance. like this;
class RestMessage extends StatelessWidget {
final String text;
RestMessage(this.text);
#override
Widget build(BuildContext context) {
return Text(text)
}
}
and then use it in the main.dart like
Column...
children: [
RestMessage(restMessageWithTime),
],

Related

Missing concrete implementation of StatefulWidget

Missing concrete implementation of 'StatefulWidget.createState'.
Try implementing the missing method, or make the class abstract.
//code
import 'package: flutter/material dart';
void main() {
run App(my App())
}
class my App extends State less Widget {
#override
Widget build(Build Context context) {
return Material App(
home: Test(),
);
}
}
class Test extends State full Widget {
State <State full Widget> create state() {
return Test state ();
}
}
class Test state extends State<Test> {
Widget build(Build Context context) {
return Scaffold(
app Bar: App Bar(),
drawer: Drawer(),
body: Text("how are you"),
)
}
}
the text in body run
Do it this way, you are having space and brackets issue on question.
import 'package:flutter/material.dart';
void main() {
runApp(myApp());
}
class myApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Test(),
);
}
}
class Test extends StatefulWidget {
const Test({super.key});
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
drawer: Drawer(),
body: Text("how are you"),
);
}
}

How do I add Widgets to a Column through code

I'm trying to add widgets to a Column dynamically. The following approach does not work as the button does not add the text widgets when clicked. I'd like to understand why this doesn't work and what should I do to make it work. Thanks in advance for the help.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
List<Widget> c = [];
return MaterialApp(
title: 'Flutter Demo',
home: Column(children: [
Column(children: c),
ElevatedButton(onPressed: (){
print("testing");
c.add(Text("testing"));
}, child: Text("Add Text"))
])
);
}
}
Edit: I edited my code to be in a stateful widget and added a setState function around the function that adds the widgets to the container, but it still won't work
import 'package:flutter/material.dart';
class SW extends StatefulWidget {
const SW({ Key? key }) : super(key: key);
#override
_SWState createState() => _SWState();
}
class _SWState extends State<SW> {
#override
Widget build(BuildContext context) {
List<Widget> c = [];
return MaterialApp(
title: 'Flutter Demo',
home: Column(children: [
Column(children: c),
ElevatedButton(onPressed: (){
setState((){
print("testing");
c.add(Text("testing"));
});
},
child: Text("Add Text"))
])
);
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SW();
}
}
void main() {
runApp(MyApp());
}
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home:MyApp()));
class MyApp extends StatefulWidget {
#override
_MyState createState() => _MyState();
}
class _MyState extends State<MyApp> {
List<Widget> c = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body:Column(children: [
Column(children: c),
ElevatedButton(onPressed: (){
setState((){
print("testing");
c.add(Text("testing"));
});
}, child: Text("Add Text"))
]),
);
}
}
Wrap your on pressed code in setstate to rebuild the page. The setState function triggers rebuild of the whole widget tree shown in your screen. And without that the text widget will only be added to the list but won't be shown to the screen.

How to set data in an inherited widget from a another widget?

So inherited widget is useful for passing data down the tree, but how do I set that data in the first place if inherited widgets are immutable?
I'm trying to set a phone number for OTP auth and then display that number on another screen. Provider is kind of advanced for me at the moment, how do I approach this?
thank you
You have to rebuild somewhere your InheritedWidget.
You can use any stage management for it, for example you can use StatefulWidget:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MyInheritedWidget extends InheritedWidget {
final int counter;
MyInheritedWidget({Key key, this.counter, Widget child})
: super(key: key, child: child);
#override
bool updateShouldNotify(MyInheritedWidget oldWidget) {
return oldWidget.counter != counter;
}
static MyInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MyInheritedWidget(counter: _counter, child: CounterWidget()),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_counter++;
});
},
),
);
}
}
class CounterWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("${MyInheritedWidget.of(context).counter}",
style: TextStyle(fontSize: 100));
}
}
Firstly you would use a StreamProvider for your stream of data (The same as you would using a StreamBuilder):
class Widget1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: Wrapper(),
);
}
}
Next widget has no required data
class Widget2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Widget3(),
);
}
}
Access your data via Provider.of
class Widget3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
if (user == null) {
return Login();
} else {
return Dashboard();
}
}
}
With this method, you still need to access the data somewhere down the widget tree. You can't go up, if you want to have the ability to have a widget up the tree listen to something that happens down the tree, you will want to look at ChangeNotifier

Why can't I get the provider package to listen to a change?

So I'm writing a very simple app, just to learn a little bit more about the provider package in flutter. The app is this:
App functionallity
When I write in mi TextField, the text bellow it should change and the title should remain unchanged, but I can't get it to listen the changes from changeText method. The code is
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Data>(
create: (context) => Data(),
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: MyText(),
),
body: Container(
child: Level1(),
),
),
),
);
}
}
class Level1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Level2(),
);
}
}
class Level2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
MyTextField(),
Level3(),
],
),
);
}
}
class Level3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(Provider.of<Data>(context, listen: false).data);
}
}
class MyText extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(context.watch<Data>().data);
}
}
class MyTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TextField(
onChanged: (newText) {
Provider.of<Data>(context).changeText(newText);
print(newText);
},
);
}
}
class Data extends ChangeNotifier {
String data = 'Hello';
void changeText(String newString) {
data = newString;
print('Hello $data');
notifyListeners();
}
}
Try putting the TextField widget inside a Stateful widget.
return TextField(
onChanged: (newText) {
Provider.of<Data>(context).changeText(newText);
print(newText);
},
);
Enclose this in a stateful widget
Also you have to add a Text controller to the textfield widget, go to docs for textfield widget in flutter.

Why is my "Data"."data" not updated in ChangeNotifier class using ChangeNotifierProvider?

I am new to flutter.
I want to ask why when my text field's onChange did not trigger: "Provider.ofContext).updateData(newString);".
The value of my Provider.of(context).data is not updated and with the 2 print statements, only 'called1' is always printed out.
Here is the code:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Data>(
create: (_) => Data(),
lazy: false,
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(Provider.of<Data>(context).data),
),
body: Level2(),
),
),
);
}
}
class Level2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
MyTextField(),
],
);
}
}
class MyTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TextField(onChanged: (newString) {
print('called1');
Provider.of<Data>(context).updateData(newString);
print('called2');
});
}
}
class Data extends ChangeNotifier {
String data = '1234567890';
void updateData(newString) {
data = newString;
notifyListeners();
}
}
You are trying to access provider in same widget where you are declaring, which is not right way to do, provider must declare in above widget where you are accessing.
Moreover always use provider data by variable(as used in MyTextField widget) other wise it will not work.
Following code may help you to understand more.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Data>(
create: (_) => Data(),
child: MaterialApp(home: Level1()),
);
}
}
class Level1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(Provider.of<Data>(context).data),
),
body: Level2(),
);
}
}
class Level2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
MyTextField(),
],
);
}
}
class MyTextField extends StatelessWidget {
var dataprovider;
#override
Widget build(BuildContext context) {
dataprovider = Provider.of<Data>(context);
return TextField(
onChanged: (newString) {
print(dataprovider.data);
dataprovider.updateData(newString);
print('called2');
},
);
}
}
class Data extends ChangeNotifier {
String data = '1234567890';
void updateData(newString) {
print("cds");
data = newString;
notifyListeners();
}
}