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

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!);
}
}

Related

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
)

Sitecore get all parent (ancestor) with little processing (performance)

I'm trying to come up with solution on getting all the ancestors for the context item. One option is to store _path in index and other option is to do similar to one below:
http://www.glass.lu/Blog/GettingAncestors
I'm having no luck with getting the solution work for above (glass mapper) solution.
I got the index solution working but would like to avoid using index just to get the _path (collection of ancestors) as we don't have any other requirements to use index e.g. search etc.
Appreciate if someone could share the snippet for working solution or even better if Glassmapper has already included the above blog solution.
The most efficient way to check if one item is a descendant of another is to simply check that the current item property Paths.LongID starts with the LongID of the parent item:
Item currentItem = Sitecore.Context.Item;
IList<Item> menuItems = GetMenuItems();
foreach (var menuItem in menuItems)
{
bool isActive = currentItem.Paths.LongID.StartsWith(menuItem.Paths.LongID);
// do code
}
This will work since the path GUIDs are unique for each item.
Alternatively, if you want to use Glass models only then you can use the SitecoreInfoType.FullPath attribute:
[SitecoreInfo(SitecoreInfoType.FullPath)]
public virtual string FullPath { get; private set; }
And then from your code you can simply check:
Item currentItem = Sitecore.Context.Item; //or use SitecoreContext() to get a strongly types model
IEnumerable<MenuItem> menuItems = GetMenuItems();
foreach (var menuItem in menuItems)
{
bool isActive = currentItem.Paths.FullPath.StartsWith(menuItem.FullPath);
// do code
}
Just a word of warning, since each menu item now need code to run in order to determine state, this will make your menu component difficult to cache, resulting caching too many variations or caching per page. You would be better to move this logic into Javascript to set the menu state using the current page URL, this will allow your component to be cached once for all pages.

Pass parameters to rendering using ItemRendering in Sitecore

I have a rendering that calls its datasources children. Each child item has a rendering attached in the renderings field.
I am calling
#Html.Sitecore().ItemRendering(item)
Which works.
However I want to pass some parameters to the child's rendering, so I tried the following code;
#Html.Sitecore().ItemRendering(item, new { Parameters = "active=1" })
But the parameters do not get passed to the child rendering when I call #Html.Sitecore().CurrentRendering.Parameters["active"]
So I tried #Html.Sitecore().ItemRendering(item, new { Active = 1 }). I called it again in the child rendering and still no luck.
Is there a way to pass parameters to the child using #Html.Sitecore().ItemRendering()
The ItemRendering method does not seem to handle properties correctly (or as one would expect!).
A work-around is to use #Html.Sitecore().Rendering() instead. You can use this in the same way as the ItemRendering method with the work-around below. Note that you should be setting the "Renderers" field of the datasource item (or its template standard values) rather than the "Renderings" field as you mentioned:
#Html.Sitecore().Rendering(item["__Renderers"], new {Datasource = item.ID, Message = "Hello World"})
In the child rendering, use the Properties property, not Parameters:
#Html.Sitecore().CurrentRendering.Properties["Message"]
var viewData = new ViewDataDictionary();
viewData["active"] = "1";
Html.Sitecore().ItemRendering(ItemToRender, viewData);
In the rendering for the Item, you can access the viewdata like this:
(ViewData["active"] != null && int.Parse(ViewData["active"].ToString()) == 1)

OSMDroid - Text overlay

I have a map of my country divider to touristic regions (PathOverlay), I wanna be able to have the name of every region above it, with just plain text, no bubbles no anything.
I've already searched how to do this but all I found was ItemizedOverlayWithFocus in the svn trunk of osmdroid.
Does anyone have any idea how to add simple text on the map (with latitude and longitude of course) ?
Sub-class Overlay (as for instance a "SimpleTextOverlay").
In the constructor or with setters, initialize your text, its position (GeoPoint), and the Paint to be used.
Then implement draw method this way:
#Override protected void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (shadow) return;
//Get the screen position:
final Projection pj = mapView.getProjection();
pj.toMapPixels(geoPosition, screenPosition);
//And draw your text at screenPosition:
canvas.drawText(text, screenPosition.x, screenPosition.y, paint);
}
Answer posted here
How to add text below/above in the middle of the polyline in osmdroid
Use the Marker overlay class, which was added to osmdroid somewhere around v5.2.
Set the title, then set the icon to null, then add it to the map (in that order)
distanceMarker = new Marker(mapView);
distanceMarker.setIcon(null);
distanceMarker.setTextIcon(distance);
distanceMarker.setOnMarkerClickListener((marker, mapView) -> true);
GeoPoint p3 = new GeoPoint((loc.getLatitude()+poi.getLat())/2,(loc.getLongitude()+poi.getLon())/2);
distanceMarker.setPosition(p3);
mapView.getOverlayManager().add(distanceMarker);

Flex/FlashBuilder :: Spark List / IconItemRenderer:: Disable Selection Highlight / No Selection / Remove Selection

I had trouble removing the selected and down state colors for a spark list using IconItemRender. If you are making a mobile app and using IconItemRender (instead of ItemRenderer) there is no autoDrawBackground property.
I figured I'd drop it in here after figuring it out thanks to this page: http://www.sajeevkumar.com/2012/01/08/flex-4-6-list-mobile-iconitemrenderer-background-image/
You can do the following to muck around with the down and selected colors. For more control over items in a list using IconItemRender look at the LabelItemRenderer class and the drawBackground function.
override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void {
var bgColor:uint = 0xffffff;
graphics.clear();
graphics.beginFill(bgColor,1);
graphics.lineStyle();
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
graphics.endFill();
// Draw the separator for the item renderer
super.drawBorder(unscaledWidth, unscaledHeight);
opaqueBackground = bgColor;
}