is this right way to send state data from parent to child - dart

Are there any other better ways to send data
import 'package:flutter/material.dart';
import './bottomNav.dart';
void main()=>runApp(Parent());
class Parent extends StatefulWidget {
State<StatefulWidget> createState() {
// TODO: implement createState
return _ParentState();
}
}
class _ParentState extends State<Parent>{
int count = 1;
#override
Widget build(BuildContext context) {
// TODO: implement build
return (
MaterialApp(
home:Material(
child:Center(
child:Child1(cont:count)
)
)
)
);
}
}
class Child1 extends StatelessWidget {
int cont;
Child1({this.cont});
#override
Widget build(BuildContext context) {
// TODO: implement build
print('context ${cont}');
return Text('This is child ${cont}',);
}
}

You can use InheritedModel for pass data between classes.
watch this

Related

How to access an attribute / method of a stateful widget from outside?

I need to access the method setBlockText() inside the _InnerBlockState class from outside to change the label of the Text Widget e.g. OuterBlock.setInnerBlockLabel(). Is this even possible? A small example is just provided below.
class OuterBlock {
Widget column;
Widget innerBlock;
OuterBlock() {
innerBlock = new InnerBlock();
initColumn();
}
initColumn() {
column = new Column(
children: <Widget>[
innerBlock
]
}
setInnerBlockLabel() {
// TODO set the text/ label from the Text Widget of the innerBlock
}
}
class InnerBlock extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _InnerBlockState();
}
}
class _InnerBlockState extends State<InnerBlock> {
String label = '';
#override
Widget build(BuildContext context) {
return Container(
child: Text(label)
);
}
void setBlockText(String label) {
this.label= label;
}
}
If I understood your problem correctly then you have two widgets. Lets call them Widget A and Widget B.
Widget B has a text variable and is USED by Widget A. You want to change the text variable in Widget A.
My solution: Pass a variable to Widget B.
Code:
// shouldn't your OuterBlock be a widget?
class OuterBlock {
Widget column;
Widget innerBlock;
String yourLabel;
OuterBlock() {
innerBlock = new InnerBlock(textVariable: yourLabel);
initColumn();
}
initColumn() {
column = new Column(children: <Widget>[innerBlock]);
}
setInnerBlockLabel() {
yourLabel = "fancy Label"; // your fancy business logic :P
}
}
class InnerBlock extends StatefulWidget {
final String textVariable;
InnerBlock({Key key, this.textVariable}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _InnerBlockState();
}
}
class _InnerBlockState extends State<InnerBlock> {
#override
Widget build(BuildContext context) {
return Container(child: Text(widget.textVariable));
}
}
Yours Glup3

Flutter: Where to add listeners in StatelessWidget?

If I were using a StatefulWidget, then I would be listening to a Stream for example inside the initState method. Where would I do the equivalent in a StatelessWidget (like to use Bloc with streams for state management)? I could do it in the build method but since these are repetitively I wondered if there is a more efficient way than checking for existent listeners like below. I know that this is a redundant and useless example but it's just to show the problem.
import "package:rxdart/rxdart.dart";
import 'package:flutter/material.dart';
final counter = BehaviorSubject<int>();
final notifier = ValueNotifier<int>(0);
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
if (!counter.hasListener)
counter.listen((value) => notifier.value += value);
return MaterialApp(
home: Scaffold(
body: Center(
child:FlatButton(
onPressed: () => counter.add(1),
child: ValueListenableBuilder(
valueListenable: notifier,
builder: (context, value, child) => Text(
value.toString()
),
),
)
),
)
);
}
}
There is no clean way to have a StatelessWidget listen to a Listenable/Stream.
You will always need a StatefulWidget.
On the other hand, you can use composition to write that StatefulWidget just once, and be done with it.
Common examples for that pattern are widgets such as ValueListenableBuilder, StreamBuilder, or AnimatedBuilder. But it is possible to do the same thing, for listening too.
You'd use it this way:
class Foo extends StatelessWidget {
Foo({Key key, this.counter}): super(key: key);
final ValueListenable<int> counter;
#override
Widget build(BuildContext context) {
return ValueListenableListener(
valueListenable: counter,
onChange: (value) {
// TODO: do something
},
child: Something(),
);
}
}
Where ValueListenableListener is implemented this way:
class ValueListenableListener<T> extends StatefulWidget {
const ValueListenableListener(
{Key key, this.valueListenable, this.onChange, this.child})
: super(key: key);
final ValueListenable<T> valueListenable;
final ValueChanged<T> onChange;
final Widget child;
#override
_ValueListenableListenerState createState() =>
_ValueListenableListenerState();
}
class _ValueListenableListenerState extends State<ValueListenableListener> {
#override
void initState() {
super.initState();
widget.valueListenable?.addListener(_listener);
_listener();
}
#override
void didUpdateWidget(ValueListenableListener oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.valueListenable != widget.valueListenable) {
oldWidget.valueListenable?.removeListener(_listener);
widget.valueListenable?.addListener(_listener);
_listener();
}
}
#override
void dispose() {
widget.valueListenable?.removeListener(_listener);
super.dispose();
}
void _listener() {
widget.onChange?.call(widget.valueListenable.value);
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
You shouldn't. Not handling variables that might have their values modified is the very purpose of a Stateless widget:
A stateless widget never changes.
UPDATE:
I think this is a problem of understanding Flutter's state management concepts. This new recommended way by the Flutter team should clear some confusions.
You could do something like this:
class ExampleWidget extends StatelessWidget {
bool _initialized = false;
#override
Widget build(BuildContext context) {
if (!_initialized) {
_initialized = true;
// Add listeners here only once
}
return Container();
}
}
But you shouldn't! In fact, your IDE will give you a warning, because this is not the way to go with Stateless widget as it is marked as #immutable. If you need to use lifecycle methods (like initState()) you should make it a Stateful widget. There's no big deal.
This is achievable with flutter_bloc package. The code to be run in initstate can be added inside BlocListener on whatever state you want.
BlocProvider(
create: (BuildContext context) =>
CategoryBlock()..add(LoadCategories()),
child: BlocListener<CategoryBlock, CategoryStates>(
listener: (context, state) {
//Example to add a listener for listview
if (state is LoadCategoriesSuccess) {
itemPositionsListener.itemPositions.addListener(() {
print(itemPositionsListener.itemPositions.value);
});
}
}
You could have your streams being instantiated in a StatefulWidget and then passed down to your StatelessWidgets as an option, so the parent widget would only have a role of controlling the lifecycle of the stream while the child would be using the stream to update the view.
Regarding the earlier answer:
There's no problem in using StreamBuilders inside your StatelessWidgets since the StreamBuilder itself is a a Widget that extends from StatefulWidget and will take care of it's own state and dispose correctly on its own.

setState not changing how to setstate StatefulWidget to StatefulWidget?

StatefulWidget to StatefulWidget
How to Change String TimeSetdata in class Test2 setstate
class Test1 extends StatefulWidget {
#override
_Test1State createState() => _Test1State();
}
class _Test1State extends State<Test1> {
String TimeSetdata = "9.00 AM";
#override
Widget build(BuildContext context) {
...
Text(TimeSetdata);
}
}
class Test2 extends StatefulWidget {
#override
_Test2State createState() => _Test2State();
}
class _Test2State extends State<Test2> {
#override
Widget build(BuildContext context) {
...
onPressed: () {
setState(() {
TimeSetdata = "11.00 AM";
});
};
}
}
How to setState in Class Test2 Change String TimeSetdata in Widget Text(TimeSetdata) to "11.00 AM";
Allow the parent to pass a callback function to the child and pass a callback, when called from the child, updates the value in the parent.
This assumes that Test2 is a child of Test1 (you didn't make this clear in your question)
typedef StringCallback = void Function(String);
class Test2 extends StatefulWidget {
Test2({#required this.onPressed});
final StringCallback onPressed;
#override
_Test2State createState() => _Test2State(onPressed: onPressed);
}
class _Test2State extends State<Test2> {
_Test2State({#required this.onPressed});
final StringCallback onPressed;
#override
Widget build(BuildContext context) {
...
onPressed: () => onPressed(),
}
}
class _Test1State extends State<Test1> {
String TimeSetdata = "9.00 AM";
#override
Widget build(BuildContext context) {
...
Test2(onPressed: (s) => setState(() => TimeSetdata = s),
...
Text(TimeSetdata);
}
}

flutter error:The argument type 'Future<Image>' can't be assigned to the parameter type 'Widget'

i'm using flutter flame library and got this error
The argument type 'Future<Image>' can't be assigned to the parameter
type 'Widget'.
my code is:
import 'package:flutter/material.dart';
import 'package:flame/flame.dart';
class TileMap extends StatefulWidget {
#override
_TileMapState createState() => _TileMapState();
}
class _TileMapState extends State<TileMap> {
#override
Widget build(BuildContext context) {
return Container(
child: Flame.images.load('grass_05.png'),
);
}
}
how to fix it?
and what's the problem?
thank's to all
class _TileMapState extends State<TileMap> {
#override
void initState() {
super.initState();
_loadImage()
}
void _loadImage() async {
var img = await Flame.images.load('grass_05.png');
setState(() => _image = img);
}
Image _image;
#override
Widget build(BuildContext context) {
return Container(
child: _image,
);
}
}

Scrollable Listview in Flutter with Dart

Can someone explain me where I should define a scroll controller? I have chat list view which is the body of a scrollable view. I want to be able to control the scrolling behaviour from MainView but don't know how to pass the controller down to _ChatListView. Any ideas?
mainview.dart
class MainView extends StatelessWidget {
...
// is this the correct place?
final ScrollController scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new ChatListView()
);
}
}
chatlistview.dart
class ChatListView extends StatefulWidget {
#override
_ChatListView createState() => _ChatListView();
}
class _ChatListView extends State< ChatListView > {
Widget build(BuildContext context) {
return ListView.builder(
controller: scrollController,
);
}
}
Add a constructor and pass the controller as parameter
class MainView extends StatelessWidget {
...
// is this the correct place?
final ScrollController scrollController = ScrollController();
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new ChatListView(scrollController: scrollController)
);
}
}
class ChatListView extends StatefulWidget {
ChatListView({#required this.scrollController});
final ScrollController scrollController;
#override
_ChatListView createState() => _ChatListView();
}
class _ChatListView extends State< ChatListView > {
Widget build(BuildContext context) {
return ListView.builder(
controller: widget.scrollController,
);
}
}

Resources