Flutter Animated Switcher with List of Widgets - list

I have a CustomScrollView with several children. One children should always be displayed but the other ones should be displayed depending on a condition:
CustomScrollView(
controller: articleState.scrollController,
slivers: [
ArticleDetailPageHeader(widget.articleShort), // <- should always be displayed
...condition
? _buildShimmerWidgets() // returns List<Widget>
: _buildArticleWidgets(context, articleState), // ยดยด
],
)
This is working. But I would like to use a AnimatedSwitcher so the UI looks a bit smoother.
I look into AnimatedSwitcher and it takes a child of the type Widget. Now that is the Problem! I have a List<Widget. Is there any workaround for this?
I hope my problem is clear, let me know if you need any more info!

Try to use a Column as the child for the AnimatedSwitcher and then pass the List<Widget> as children for the Column.

Related

DART/FLUTTER: How to get access to member variable / values of Widgets

I have an list of widgets. The widgets are background images for a website. The last widget(image) in this list is displayed onscreen. As nav functions push/pop, the last element is removed/added.
One of the fields in the Widget(BackdropImage) is a bool called 'isForeground'. I need access to it.
Why? Some background images are foreground and are to be rendered above the site's semi-transparent background texture, some are to be rendered behind it.
If I have a List(BackDropImage) and the BackDropImage contains:
Path, BoxFit, Opacity, isForeground(bool) etc etc. How can I get access to the last BackDropImage in BackDropImage list and access its isForground field?
//PSUDO WIDGET TREE:
if(backdropImageList.last's 'isForground' field is FALSE) BackDropImage.last,//render here below the texture
BackgroundTextureWidget,
if(backdropImageList.last's isForground field is TRUE) BackDropImage.last //render here above the texture
HeadingWidget,
OtherWidgets
I'd appreciate help if possible (or alternative approaches). The alterative is to flip a bool programmatically every time a button is pressed/popped and keeping track of what images are displayed where. Knowing which images are fore/background in the first place and controlling from the object itself is much neater IMO.
Thanks folks.
list.firstWhere((x) => x['isForground'] == true);
Widget is an abstract class. When working with Widgets like Container etc that have member variables you need to access programmatically, it can be done like this:
Widget testContainer = Container (width:100)
print(testContainer.width) // WON'T WORK
print((testContainer as Container).width) // WILL WORK
To access the member variables of individual Widgets in a list of Widgets:
List<Widget> listOfWidgets = [Container(color:Colors.blue), Container(color:Colors.red), Container(color:Colors.green)]
void printColorsOfAllContainers () {
for (var element in listOfWidgets) {
if (element is Container) {
print(element.color);
}
}
}
Alternatively, you can also do things like this:
void printColorsOfAllContainers() {
final List<Color> listOfContainerColours = [];
for (var element in listOfWidgets) {
element as Container;
listOfContainerColours.add(element.color!);
}
}

Flutter Expanding List Optimisation, Performance and Best Practices

What is the best practice for displaying a list of Widgets in flutter, where the list can be extended or reduced in length via State.
Let's say we have a Provider State that determines the length and we render widgets accordingly.
List _state = Provider.of<Somesuch>(context).routes;
for(int i = 0; i < _state.length; i ++)
Container(child: Text('Item $I'),
The problem on testing this is that if the state length increases, all child widgets seem to be rebuilt. Due to the number of animations contained in each actual child, this does not seem to be an optimal approach.
We have experimenting with nesting the children:
class NestContainer extends StatelessWidget {
NestContainer({
this.child = const SizedBox(),
this.nextChild = const SizedBox(),
});
final Widget child, nextChild;
}
Widget build(BuildContext context) {
return Stack(children:[
child,
nextChild,
]);
}
then as the child of some Widget:
Builder(builder: (context) {
List _state = Provider.of<Somesuch>(context).routes;
buildContainer(int index){
return NestContainer(
child: Container(child: Text('Item $index')),
nextChild
: _state.asMap().containsKey(index + 1) ?
buildContainer(index + 1) : const SizedBox()
}
return buildContainer(0);
});
This seems to not cause the rebuilds but I am concerned about the use of functions as this is discouraged in the docs.
Also it makes passing actual content to these children for more involved as technically all potential children (that are actually page routes contained in a Map). Each NestContainer would need to receive the whole Map so that it can render the correct item from it which means passing a lot of unused data to every single NestContainer.
What is the best approach for dealing with this matter?
Keys are important. They allow flutter to look at a stack of widgets as a whole and determine whether anything inside that stack has changed.
List _state = Provider.of<Somesuch>(context).routes;
for(int i = 0; i < _state.length; i ++)
Container(key: ValueKey('Container $I'), child: Text('Item $I'),
The addition of that key means that if that container does not change and it's place in the list does not change none of it will be checked for a change.
However, this is not the full answer. Memory usage is based around a number of rendered widgets on screen among other things. Getting rid of anything not on screen is important.
Many will say that the best way is to remove unused widgets from the tree. ie
Stack(children:[
someStatefield ? SomeWidget() : SizedBox()
])
This is true but it is not always possible particularly in a complex navigator. The idea is instead to replace widgets that can't be seen on screen with the minus amount of content possible until they are needed to be seen again.
The easiest way is to use the Visibility class. With Visibility(visible: false), the child of this class will be replaced with a SizedBox and it's content restored when set to true. Adding maintainState: true will allow it to maintain responses to any other state changes without rendering any content or performing any anumations until it's visible again.
Visibility(
visible: (true or false based on your state),
maintainState: true // ensures the child still responds to changes in state despite rendering no content or animations
child: // Your Widgets and content that will be replaced by a SizedBox when not visible
)

Webix layout as template

I'm new to Webix and trying to create a list or dataview where users can add and remove itens. (font files this time)
For such i defined one "add" button and one list where previously added items are displayed.
My plan was to put an label and a exclude button into each item of the list with the components Webix already provides but to my surprize the template property of data components aparentily can't be definied with ui objects itself.
There is some way to do it?
Somethink like it:
webix.ui({ id:'stage', rows:[
{ view:"button", type:"icon", icon:"plus", label:"Add Font", autowidth:true, click:AddFont },
{ view:"dataview", id:"fnt_list", data:fonts(), width:300,
type:{ width:300, height:150, template:function(fnt)
{
return webix.ui({cols:[
{view:"label", align:"left", label:fnt.fileName },
{view:"button", type:"icon", icon:"trash", label:"Exclude", align:"right", autowidth:true }
]});
}}
}]});
I know it can be made with the layout component alone but i really would like to do it with one of the data components because of the paging feature they have.
While it possible to create a separate instance of webix UI for each row, it is overkill for your task, just use HTML markup in the template. Something like next
{ view:"dataview", css:"fonts", id:"fnt_list", data:fonts, width:300,
type:{
width:300, height:150,
template:"#fileName# <i class='fa fa-trash-o'></i>"
},
working snippet - https://snippet.webix.com/dvbdt6st
If you still want to have real UI widgets inside of dataview items, check
https://docs.webix.com/desktop__data_layout.html
and
https://docs.webix.com/desktop__active_content.html

How to dynamically change the list data when click on picker 'done' button in Sencha Touch

I am developing my application in Sencha touch. In that I have a list and Picker and I want to update the list data dynamically when selecting the picker i.e., I want to add data to list dynamically when tap on 'Done' button of Picker. I used some logic for this but this doesn't update the list content.
listeners: {
change: function(picker,value) {
textValue = picker.getValue()['name'];
var me = this,
nameList = this.down('#namesList');
nameList.add({fullname:textValue}) ;
}
}
When I update like this, it throws me the error that 'Uncaught TypeError: Cannot call method 'add' of null' eventhough 'namesList' is already defined. Please show me the way to solve this problem.
I would add a record to the data/store of the list, and then capture the list and refresh.
The issue there is that nameList isnt actually the list component.
Try adding for example an id to the list, and then in the picker change listener:
Ext.getCmp('mylist-id').refresh()
Hope it helps.

Animation on sencha touch 2 list item

I have a list extending Ext.dataview.List.
I would like to play an animation in only one of the list items.
If it is triggered by the itemTap, it is easy, because the callback provides a third argument, I just run the animation on it. (I mean Ext.Anim.run).
But what if I need to animate the n-th element independently from the list, like triggered by a user tap on a separate button?
Thanks
Let's say you have a list which has the following config :
xtype:'list',
cls: 'myList',
...
Then you can access its DOM element with :
var items = Ext.DomQuery.select('.myList .x-list-item');
It will returns all the items of the list with the cls 'myList' so be sure to have only one list with this class.
From there you can do whatever you want with it like hiding the second item :
items[1].style.display = 'none';
Hope this helped