Is That Possible To Change the Widgets Styles and Action According to the Api Data's? - flutter

For Example Assume You Have List of 10 Postive and Negative Values. So We can Go with ListView Builder. Now what the Changes Should be Happen is If the Positive Value Should Take as Green Card in Listview if the Value is Negative the It Should Show Red Card...

Sure you can do that, I am assuming that you are receiving JSON from API.
i.e. balance is the value you want to check. if it has a negative value then use logic
like below(psudo code)
if( balance > 1000){
//... the used green colour in widget
} else {
// use color red in widget
}

Yes you can do that.
Widget greenCard() {
return Card(
//green card
);
}
Widget redCard() {
return Card(
//red card
)
}
And call these functions like this in widget tree.
Widget build(BuildContext context) {
// other widgets in tree
// in listview builder
(value >= 0) ? greenCard () : redCard(),
//other widget in the tree
}

The simplest way to do this in thru if else condition
Example Code:
if (list[index].value == "positive")...[
Card(
color: Colors.green,
)
] else...[
Card(
color: Colors.red,
)
],
or
Card(
color: list[index].value == "positive"
? Colors.green
: Colors.red
)

Related

How to Set the Loading Value for the Circular progresss Indicator like progress percentage for 60 days in flutter?

How to Set the loading value for the Circular progresss indicator like progress percentage in flutter for 60 days-Math formula?I need this stuff for my flutter project,Sorry if i am asking something silly:-)
Note: I'm new to this amazing flutter development.
You can set "completed" rate of a progress indicator like this:
CircularProgressIndicator(value: 0.5)
The above will result in a 50% indicator. All you have to do is use a member as value in a StatefulWidget and use setState to update it according to the desired percentage.
Also you can use it to indicate the progress when loading an image:
Image.network(
'<url>',
height: 50,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
);
},
)

Change divider color on DataRow only for rows and not for heading

I would like to change the divider color in a DataRow in a DataTable, only for the rows and not for the header row.
I can wrap the DataTable in a Theme widget to change the color
Center(
child: Theme(
data: Theme.of(context).copyWith(dividerColor: Colors.grey),
child: DataTable(columns: [
DataColumn(
//....
but this affects also the headingRow
is there a way to prevent this? thank you
This is not possible using the default DataTable because DataTable uses the same Divider for every row including the header row.
But if it is really necessary, I have changed a little bit of code in the data_table.dart file that defines DataTable. this will get you what you want although changing the library files is not good practice:
Add this instead of line 893 - 909:
final BorderSide borderSide = Divider.createBorderSide(
context,
color: Colors.red, // Add this color for your data rows.
width: dividerThickness
?? theme.dataTableTheme.dividerThickness
?? _dividerThickness,
);
final BorderSide borderSide2 = Divider.createBorderSide( // Adding this divider for the header row.
context,
color: Colors.blue, // The color of your header row divider.
width: dividerThickness
?? theme.dataTableTheme.dividerThickness
?? _dividerThickness,
);
final Border? border = showBottomBorder
? Border(bottom: borderSide)
: index == 0 ? null : index == 1 ? Border(top: borderSide2) : Border(top: borderSide); // Changed this that the first row uses the other divider.
The result:
the result

Moving a dynamicaly generated Positioned Widget in Flutter

How can I move an Positioned Widget in Flutter that was created at runtime?
Szenario:
Lets say I have a Stack Widget. The children are a variable of type List<Widget>[].
I receive the command to create a new Positioned Widget.
A second stream sends updated x and y positions, those I want to apply on left and top of the dynamically created Positioned Widget.
To do this I added two variables to my class and set them to left and top of the Positioned Widget.
While this works as along as the Positioned Widget is created during build time, it does not work when I dynamically add the Widget to the List<Widget> at runtime. (the Positioned Widget appears, but i can not change left/top through the variables of _MyClass)
Some pseudo code that shows the bits.
class _MyClass extends State<StatefulWidget> {
double x = 0.0;
double y = 0.0;
List<Widget> myList = [];
[...]
void _updateLocation(dx, dy) { // called by a stream...
setState(() {
x = dx;
y = dy;
});
}
[...]
void addHeart() {
myList.clear();
myList.add (
Positioned(
top: y,
left: x,
child:Icon(
Icons.favorite,
color: Colors.pink,
size: 24.0,
),
)
);
}
[...]
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Demo"),
),
body: Center(
child: Container (
child: Stack(
children: myList, //this does not update the top/left of the object
/* //THIS WORKS
children: <Widget>[
Positioned(
top: y,
left: x,
child:Icon(
Icons.favorite,
color: Colors.pink,
size: 24.0,
),
)
]
*/
)
)
),
);
}
I'm new to Flutter, and I propably don't get the mechanics right here, though, I tried to get this working with setState and Keys, but I feel like I'm missing a important bit of information here.
A possible hack I found is to provide the List<Widget> through a function to the Stack Widget and rebuilding the List<Widget> everytime I get an update on x and y. Which essentially deletes and adds the Widget from the stack everytime I get a new x and y... This seems like the worst way to achieve what I want.
How can I do this in a better way, what I'm missing here, why can I update top/left through x and y when creating the widget in build(..) but not when adding it to the list at runtime?
Ofcourse it would not work when you have a predefined list as children of stack. For your widget to move and change its location, flutter needs to actually rebuild the changed widgets, and note that it does call build method each time it re-renders.
So it is not a bad solution to call a function which creates the list each time (as it is exactly what flutter does for all widgets).
You do not need to worry about adding and deleting the items of stack each time the function is called, that is because flutter does not actually re-render anything on the page if it has not changed compared to current content of the page.

Flutter: How do I stretch the last Element in a Wrap Widget?

I think this doesn't need much explaining so I didn't include any code or screenshots.
As the title, suggests, I have a Wrap Widget and I want the last Element of it to take up all the available horizontal space to the right, (the same way as if you put an Expanded Widget in a Row).
I this case though, I can not use Expanded or Flexible, as Wrap doesn't allow that.
Edit, added a bit of (simplified) code and screenshots:
_buildTileDragTarget is just a function that returns a DragTarget.
void _buildAnswerWidgetsFromStrings() {
_answerWidgets.clear(); //start building from 0
_answerWidgets.add(_buildTileDragTarget(index: 0)); //add initial DragTarget
//for each word in _answerStrings, add Draggable Chip & DragTarget
for (int i = 0; i < _answerStrings.length; i++) {
WordTile wordTile = _answerStrings[i];
_answerWidgets.add(
Draggable<WordTile>(
key: UniqueKey(),
data: wordTile,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
child: Chip(
label: Text(wordTile.word),
padding: EdgeInsets.all(0),
),
onTap: () {
//seems to work: tap from top to bottom (5)
setState(() {
_options[wordTile.word] = true;
_answerStrings.remove(wordTile);
});
},
),
feedback: Material(child: Chip(label: Text(wordTile.word))),
childWhenDragging: Chip(label: Text(' ' * wordTile.word.length)),
),
);
_answerWidgets.add(_buildTileDragTarget(index: i + 1)); //the position AFTER the current word (last)
}
//remove last DragTarget and add one wrapped in Expanded
_answerWidgets.removeLast();
_answerWidgets.add(
SizedBox(
// width: double.infinity,
child: _buildTileDragTarget(index: _answerStrings.length),
),
); //TODO try wrapping the whole thing in 1 big DragTarget (for last index)
// _answerWidgets.add(_buildTileDragTarget(index: _answerStrings.length));
}
Screenshots:
I wrapped the Wrap widget in a purple Container, each DragTarget is wrapped in a green Container. (you can ignore the blue part)
(1) This is what I have (without SizedBox)
(2) This is what I get when I try using SizedBox(width:double.infinity...)
(3) This is what I want
Try SizedBox(width: double.infinity)
There's also expand constructor you might use
SizedBox.Expand(
child: //your widget
)

Is that possible to cache widget to resue?

I am using getbody() method to get app body and the getbody() return a Widget If i change the variable ct count the the getbody() will return different widget and each widget is stroied in Listqueue<MyPage()> if i set variable ct value 1 it return widget from my list at position 1 and if i set variable ct 2 then it will return corresponding widget .
But the problem is in each widget i am doing an api call but when i reuse that widget it is again calling the API call and why this is calling after first time nd how to stop calling api when i am reusing the widget
ListQueue<Page> page1, page2, page3, page4;
_AppFramePageState() {
page1 = ListQueue();
page1.add(Page(widget: AppHomePage(), title: "Home Page"));
page2 = ListQueue();
page2.add(
Page(widget: TemplesListing(), title: "Temple listing"));
page3 = ListQueue();
page3.add(Page(widget: AppCommunities(), title: "Communities"));
page4 = ListQueue();
page4.add(Page(widget: AppVideos(), title: "Media"));
}
If user click on cart button from toolbar then i will add more value to page1 list and if user click on back button then i will remove last item from page1 list
Widget getBody() {
//This code is solved my 50% issue but renaming 50% is there. How to solve this issue?
return IndexedStack(
index: _selectedIndex,
children: <Widget>[
page1.last.widget,
page2.last.widget,
page3.last.widget,
page4.last.widget
],);<br>
//This is the code i used first time
switch (_selectedIndex) {
case 0:
return page1.last.widget;
case 1:
return page2.last.widget;
case 2:
return page3.last.widget;
case 3:
return page4.last.widget;
}
}
class Page{
Widget widget;
String title;
Page({this.title,this.widget});
}
Note: All widgets are StatefulWidget
In general, it's not possible to reuse the widgets.
You can manually reuse the cache widget by comparing old and new state of the widgets. Which is very lengthy and i don't think you should follow it.
There are many State management architecture patterns like Provider, BLOC, MOBX etc. to manage your app in a great way. They are used to improve your app performance and decrease widget re-renders, manage data flow across the whole app etc.
One more thing you can do to make your Stateful widgets more impactive by using the const keyword whenever possible.
like for following widget ,
Column(
children: <Widget>[
// Widget 1
Center(child: Text(dynamic_value),),
// Widget 2
Container(
child: const Center(
child: const Padding(
padding: const EdgeInsets.all(10),
child: Text("Hello"),
),
),
),
],
)
In above example for Widget 1, you can't use "const keyword" as it depends on "dynamic_value".
While for Widget 2, you can use the "const keyword" which will be useful if your build method gets called again then "Center", "Padding" & "Text" widgets will be not called again as they are declared as constant widgets.