getting height of a widget in flutter - flutter

I have made a list of widgets
List<Widget> my_list = [Text("Hello World"),Text("Hello Flutter")];
And I want to make a Widget which takes argument as list of widgets only in its constructor, and I have to do something using this widgets in which I need the size of each widget. Below is my Widget
class MyCustomWidget extends StatefulWidget{
List<Widget> widget_list;
MyCustomWidget(this.widget_list);
#override
_MyCustomWidgetState createState() => _MyCustomWidgetState();
}
class _MyCustomWidgetState extends State<MyCustomWidget>{
List<double> widget_height;
#override
Widget build(BuildContext context) {
return null;
}
}
In this list(widget_height) I have to save the height of each widget that is in the list(widget_list).
How to do this.
Is there any method like widget_list[0].getHeight()?
Edit: I can't use global key. Refer comment section for more detail.
And I need all this data before rendering the object. So maybe we can override initState() method to get all this data betfore rendering.
Maybe I an not correct in the last part about rendering.

Related

Child widget not updating parent widget when child parameter changes

I have a child stateful widget that isn't updating the parent widget when an update to one of the parameters occurs.
The parent widget (OtherListVIew) is used to display a list of items on a PaginatedGrid with each item having a checkbox. The problem is that when a user views the page and there are selected items that are retrieved by the _retrieveItems() the changes do not reflect since at this point the ui is already rendered on the screen with the original empty list. These retrieved values do not reflect on OtherListView (_selectedItems is then used to display the checked items).
In this child widget I have the code
List<String> _selectedItems= [];
#override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
_retrieveItems(); // this function retrieves items and reinitializes _selectedItems
});
}
#override
Widget build(BuildContext context) {
return SomeListView(
key: _listViewKey,
selectedItems: _selectedItems,
);
}
SomeListView looks as below
class SomeListView extends OtherListView {
const SomeListView ({super.key, super.selectedItems});
#override
State<SomeListView > createState() => SomeListViewState();
}
class SomeListViewState extends OtherListViewState<SomeListViewState> {
// override some method here from OtherListView for customization purposes
#override
Widget build(BuildContext context) {
return super.build(context);
}
}
OtherListView is the parent class that contains the PaginatedGrid that renders the passed _selectedItems to the UI. Why is it that after the _selectedItems have been refetched they are not reflecting on OtherListView? Is this an issue with my state management?
I have attempted using didUpdateWidget under OtherListView and indeed I can see the new values under the newWidget but they are not rendered on the UI. What I'm I missing?
#override
void didUpdateWidget(covariant T oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.selectedItems != oldWidget.selectedItems) {
log.info('OtherListView selected items have been updated.');
}
}
OtherListView extends StatefulWidget {
final List<String>? selectedItems;
const OtherListView({Key? key,this.selectedItems})
: super(key: key);
// ...
}
honestly i don't understand your code but the problem you are facing the parameter is not updating because with setState it will only rebuild the parameter/state/variables that are in the same screen/class widget where the setState is called so you have to raise your parameter to the parent screen then pass it to the child with constructor and create a constructor in your child for function onTap for example then in the parent screen you use that onTap and called setState inside

How should I implement the init method? In a stateful or stateless widget?

What is the rule of thumb to use an initial method for a widget. Shall I use the:
A. classical stateful widget approach?
Or is it better to stick with the B. stateless widget approach?
Both seem to work from my testing. In terms of code reduction, it seems the B. approach is better, shorter, cleaner, and more readable. How about the performance aspect? Anything else that I could be missing?
Initializing a controller should be a one-time operation; if you do it on a StatelessWidget's build method, it will be triggered every time this widget is rebuilt. If you do it on a StatefulWidget's initState, it will only be called once, when this object is inserted into the tree when the State is initialized.
I was looking for initializing some values based on values passed in constructor in Stateless Widget.
Because we all know for StatefulWidget we have initState() overridden callback to initialize certain values etc. But for Stateless Widget no option is given by default. If we do in build method, it will be called every time as the view update. So I am doing the below code. It works. Hope it will help someone.
import 'package:flutter/material.dart';
class Sample extends StatelessWidget {
final int number1;
final int number2;
factory Sample(int passNumber1, int passNumber2, Key key) {
int changeNumber2 = passNumber2 *
2; //any modification you need can be done, or else pass it as it is.
return Sample._(passNumber1, changeNumber2, key);
}
const Sample._(this.number1, this.number2, Key key) : super(key: key);
#override
Widget build(BuildContext context) {
return Text((number1 + number2).toString());
}
}
Everything either a function or something else in widget build will run whenever you do a hot reload or a page refreshes but with initState it will run once on start of the app or when you restart the app in your IDE for example in StatefulWidget widget you can use:
void initState() {
super.initState();
WidgetsBinding.instance!
.addPostFrameCallback((_) => your_function(context));
}
To use stateful functionalities such as initState(), dispose() you can use following code which will give you that freedom :)
class StatefulWrapper extends StatefulWidget {
final Function onInit;
final Function onDespose;
final Widget child;
const StatefulWrapper(
{super.key,
required this.onInit,
required this.onDespose,
required this.child});
#override
State<StatefulWrapper> createState() => _StatefulWrapperState();
}
class _StatefulWrapperState extends State<StatefulWrapper> {
#override
void initState() {
// ignore: unnecessary_null_comparison
if (widget.onInit != null) {
widget.onInit();
}
super.initState();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void dispose() {
if (widget.onDespose != null) {
widget.onDespose();
}
super.dispose();
}
}
Using above code you can make Stateful Wrapper which contains stateful widget's method.
To use Stateful Wrapper in our widget tree you can just wrap your widget with Stateful Wrapper and provide the methods or action you want to perform on init and on dispose.
Code available on Github
NOTE: You can always add or remove method from Stateful Wrapper Class according to your need!!
Happy Fluttering!!

Updating column on user input flutter

I am making a chat program and need to update a column of widgets of chatBubble with user input. But I am unable to do that because of immutable widgets of flutter. What can i do?
Initiate a new Stateful Widget for column :
class Chat extends StatefulWidget {
#override
_ChatState createState() => _LoginState();
}
class _ChatState extends State<Chat> {
#override
Widget build(BuildContext context){
return Column(children://your Widget's list
)}
And the update your widget's list by using setState() inside your function. Then this column will be redrawn with the new widgets' list.
Example :
void changeChat(newWidget){
setState((){
//append the newWidget to your list of widgets.
})}

Trying to access state from widget, probably using wrong design

I'm learning flutter and trying to make a kind of MutableImage widget. The idea is to make a MutableImage StatefulWidget that would rebuild when a new image is provided. I try to avoid rebuilding the whole widget tree each time the image is changed because that seems overkill, and I plan to update the image several times per second. So I want to rebuild only that MutableImage widget.
So here is the code I have, with comments to explain where I'm stuck :
class MutableImage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MutableImageState();
}
void updateImage(List<int> bytes) {
// !!!!!! Would like to call this method here, but state is not available from Widget, which means I want to do something wrong, but not sure exactly how I should do it...
// this.state.updateImage(bytes);
}
}
class MutableImageState extends State<MutableImage> {
List<int> _bytes;
void updateImage(List<int> bytes) {
setState(() {
_bytes=bytes;
});
}
#override
Widget build(BuildContext context) {
if ((_bytes==null)||(_bytes.length==0)) {
return Center(child: CircularProgressIndicator());
}
return Image.memory(_bytes);
}
}
Then the idea was to use this widget like this for example in another stateful widget
MutableImage _mutableImage;
#override
Widget build(BuildContext context) {
if (_mutableImage == null) _mutableImage=MutableImage();
return : Row( //using Row as an example, the idea is that the mutable Image is deep into a tree of widgets, and I want to rebuild only _mutableImage when image changes, not all widgets.
children : <Widget>[
child0, child1, _mutableImage, child3, child4
]
);
}
void updateImage(List<int> bytes) {
_mutableImage?.updateImage(bytes);
}
So is there a good way to do this ? I'm quite confused, thx for any help/hint.
This is a place for an application of a GlobalKey. In the parent Widget of MutableImage make a global key and pass that to MutableImage. With that key you can access MutableImage state by using .currentState on the key and calling updateImage.
You'll have to add key as an argument of the MutableImage constructor and call super(key: key). updateImage should also be moved the the state of MutableImage.
Key:
final GlobalKey<MutableImageState> _imageKey = GlobalKey<MutableImageState>();
Pass the key:
MutableImage(key: _imageKey);
Access the state:
_imageKey.currentState.updateImage();

Flutter: How can I avoid recreating the model for parts of the application?

My app uses a set of Card()s inside a PageView(), each card has multiple text lines.
The user gives input for each line (e.g. modifying the text etc.).
I want to keep this input for a while.
This is how my code looks at the moment, abstractly speaking:
class MyCard extends StatefulWidget {
final List<Widget> _myLines = [];
#override
State<StatefulWidget> createState() => MyCardState();
}
class MyCardState extends State<MyCard> {
...
#override
Widget build(BuildContext context) {
...
widget._myLines.add(ChangeNotifierProvider(
create: (context) => MyLineModel(context, lineText),
child: RecipeLine())
...
}
}
This doesn't work well:
As soon as I swipe left / right through the PageView onto other cards and then swipe back, the Card is being built again. This also leads to a rebuild of MyLineModel, which in turn erases all the user's input.
How can I avoid the rebuild of MyLineModel and keep the user's input?
You can solve this in 2 ways:
Create the model outside the widget and pass the model for the widget, as a variable to a constructor for example, or using Provider or any other technique of Dependency Injection.
Using any of the KeepAlive APIs, such as the AutomaticKeepAliveClientMixin as:
class MyCardState extends State<MyCard> with AutomaticKeepAliveClientMixin {
...
#override
bool get wantKeepAlive => true;
}
As the official documentation states, we can simply use the ChangeNotifierProvider.value() constructor...
In the original code:
class MyCardState extends State<MyCard> {
...
#override
Widget build(BuildContext context) {
...
widget._myLines.add(ChangeNotifierProvider.value(
value: MyLineModel(context, lineText),
child: RecipeLine())
...
}
}