Flex component setActualSize - apache-flex

I am a little confused about the setActualSize method. It appears from what I've read, that if it is not called on a component by its parent, the component will not be rendered.
So it appears that setActualSize is a critical method that is directly bound to rendering the UIComponent. It also appears that the width and height properties of UIComponent override the functionality of the width and height properties of flash.display.DisplayObject, in that they are not directly bound to the rendering of the object but are virtual values that are mainly used by the getExplicitOrMeasured when the parent of the component calls the component's setActualSize method.
So the question are:
1) Why isn't the default behavior of every component to just call setActualSize(getExplicitOrMeasuredWidth(),getExplicitOrMeasuredHeight()) on itself?
2) I guess this question stems from the above question and the behavior as I understand it as described above: does setActualSize change the visibility of the component?
It appears that that the behavior is that a component is not rendered until setActualSize is called, but if it contains display object children itself (expected behavior as it can calculate measure on itself) and is added to the display list, the only reason why flash isn't rendering it, is because its not visible.

The answers to your questions are in the way the Flex component life cycle works, consider these two phases:
measurement:
The Flex framework will call the measure() method of your component. You can override this method to set a default and/or minimum size for your component.
Flex components first measure themselves to provide a default and/or minimum size suggestion to the layout/container classes. Flex does this from a bottom up approach, so that the lowest level objects are measured first. Thus when each parent object measures itself, the preferred sizes of it's child objects has been established.
rendering:
Later Flex calls the updateDisplayList() method of your component. You can override this to size/position your component's child objects. This is where setActualSize() is intended to be used: the parent calls setActualSize() on it's child objects, not on itself.
Note the method signature of updateDisplayList():
protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
Measurement was done from the bottom up. However, rendering is done from the top down. So at render time, updateDisplayList(unscaledWidth, unscaledHeight) gets executed on your component. Flex is telling your component the space it has been allotted to render itself, and your component must size/position it's child objects accordingly and/or do programtic drawing.
The sizes passed in to updateDisplayList() are based on various factors:
how/if you override the measure() method (measure is not called when
your component has a fixed width/height)
the types of sizing
parameters (fixed, percent, constraint) and layouts that you use
An old but good resource on this topic

setActualSize() is one of the crutial and most interesting methods in Flex layout process:
1) Notice that setActualSize() is an entry point for parent's layout to set the component size, and it has to be called by parent (container) almost exclusively!
This is because only the parent knows the amount of space available for each child (this method is being called after all children are measured and the container knows it's own given size).
(note: the example of not calling it by layout posted below)
This method exists because if parent would set 'width' and 'height' on children directly, they would immediately turn into fixed size children, and they won't be measured anymore.
Using this method, only the rendering size is being changed - not the (explicit) width and height but _width and _height - meaning if for some reason the container resizes again, the children will be resized by given rules (percentage of the parent, expanding to child component's children size etc.)
2) Yes, because if this method isn't called at all, the component has a (rendering) size of (0, 0), so this is the reason of it's invisibility (not setting 'visible' to false)! ^_^
Note that THERE HAS TO BE A LAYOUT (even a non attractive one) to trigger this method call. By 'non attractive' I consider the layout that isn't supposed to do anything smart, like CHANGE THE WIDTH AND HEIGHT of children at all (like absolute layout)!
Now, look at the PopUpManagerImpl's class addPopUp() method: there is an interesting case of calling setActualSize():
IUIComponent(window).setActualSize(
IUIComponent(window).getExplicitOrMeasuredWidth(),
IUIComponent(window).getExplicitOrMeasuredHeight());
Explanation: PopUpManager does stuff that layout should normally do, because it WANTS TO KNOW THE POPUP DIMENSIONS IMMEDIATELY, so it could center the popup on stage. It has no time to wait for the layout pass!
If you comment those 3 lines in the framework code, you'll see that popup is being centered with it's top left corner - just like it's size is (0, 0). Anyway, it is rendered with proper width and height because at rendering time the dimensions are known.
Hope this makes things a bit clearer...
Cheers! ^_^
Danko Kozar

Related

Getting width/height in a slotted lit-element in Edge

I've got one lit-element, inner-element, slotted into another lit-element, outer-element. For flexibility, the outer-element gets to set the width and height of the inner-element using CSS. The inner-element needs to know it's width and height to determine how to draw its SVG content.
How can inner-element reliably learn its own width and height across browsers?
I've got a live example here:
https://stackblitz.com/edit/7pkfkx-j9rnx9
I'm using updated() to get the width/height based on this very helpful information:
https://github.com/Polymer/lit-element/issues/507#issuecomment-459546838
In Chrome, the example works fine - the SVG displays "width = 150 height = 100". But in Edge, I get "width = 300 height = 303.8". Note that even in Edge, the inner-element ends up having the correct width and height (150x100), it just seems to be getting there after updated() has been called.
I don't have access to Edge in order to confirm, but there are a few things you might be interested in testing here.
1) In your index.ts you have the following code:
import './inner-element.js';
import './outer-element.js';
This means that the inner element, will register and upgrade before the outer element has been registered and upgraded, which means that its size will be determined initially as if outer-element is a div, and then subsequently be granted the slotted styles inside of outer-element. Swap the imports to prevent this specific race order from occuring.
2) You are measuring in firstUpdated() which can technically happen before the element hit's the page, meaning that you are measuring an unrendered element, which is an element that has no size. Waiting until connectedCallback() can ensure that you are measuring the element "in page".
3) Measuring the element synchronously means you might be measuring before all of the parent based/classed based/etc code has been run, using requestAnimationFrame() in connectedCallback() can help ensure that you aren't measuring until you can be 100% sure that the element is ready to be measured.
Try this demo out to confirm: https://stackblitz.com/edit/measure?file=inner-element.js
I've discovered that a reliable way to get the rendered width and height of the inner-element is to access them in a window.setTimeout() callback registered in firstUpdated().
This is demonstrated here.
Whereas the LitElement doesn't always have access to its own rendered width and height when its' updated() or firstUpdated() is called, it does seem to have access to these values when the timeout callback is called.
I would feel more comfortable marking this answer as correct if I could articulate why this is the case, but empirically it is working.

Difference between visible and includeInLayout properties of a component in Flex

Can anybody please tell me what about visible and includeInLayout properties of a component and what is the state of the component when they are in combination of {false,false},{false,true},{true,false}. Thank you in advance.
Ok, visible is only about visibility of component and includeInLayout is only about taking part in process of component's laying out. Talking about laying out we're talking about such layouts as vertical layout, horizontal layout or tile layout where positions of the children determines by positions of other children.
Well, according to this explanation false,false is about target display object will not visible and will not affect on the position of other objects in layout. It is the same as target display object isn't exist at all.
The case false,true describes the situation where target display object isn't visible but takes part in layout. For end user it is an empty space between other objects in layout. This space has the same dimensions as our target display object.
The case true,false makes target display object visible but with not predictable position (depends on the particular layout implementation). Anyway it is not affect other elements position which laying out the way as target display object doesn't exist. It is very likely some of the other element overlap our target display obje

Update UIComponent size

I've created a AS3 class which extends UIComponent so that I can easily add it to my MXML layout. It works fine, but I'm trying to figure out how to update the UIComponent width and height dynamically. I want my super UIComponent to draw a border around the content, so I need get the specific 'content' dimensions in order to do this.
I understand the idea of UIComponent is that you are supposed to specifically set the width and height... but I am literally only extending it so that I am able to use my custom component with MXML easily.
Is there a method in which I can get the width and height of a UIComponents 'content'?
Thanks
Like Robusto described in his comment, the Canvas is probably a better choice if you're trying to add children to it. The Canvas instantiates a CanvasLayout, which handles all the complex logic for sizing itself and children.
The width and height of a UIComponent's content is determined in the measure() method, unless the UIComponent has explicit or percent sizes defined. Measure is one of those methods that aren't well documented. I suggest Diving Deep into the Flex Component Lifecycle with EffectiveUI. They go into the lifecycle methods and really explain how to use them.
The measure() method is called if the parent (your component) doesn't have any sizing defined. Then it goes through all of its children, calculates their sizes, and sums them up into measuredWidth and measuredHeight. The parent's sizes are then set to those values.
If you extend UIComponent, you have to do a lot in the measure method to handle all the edge cases: explicit, percent, constraints (top, left...), padding, whether or not includeInLayout = true, etc. Canvas does all that. Same with the other container components: Box, HBox, VBox, List, etc.
Hope that helps,
Lance
Not sure what you mean by the "content" of your UIComponent. Do you mean the UIComponent's dimensions, or a child container's?
One place you can look for the size of any component is in its updateDisplayList method, which is a protected method you would have to override, as so:
override protected function updateDisplayList(width:Number, height:Number) {
super.updateDisplaylist(width, height);
// your statements here
}
You say you are extending UIComponent only so that you are able to use your custom component "with MXML easily." But you still need to extend it as much as you need to in order to do what you need to do. For that you should learn about the lifecycle of a component, when to overrwrite the createChildren(), commitProperties(), measure() and other methods, and so on. It's really not hard, and you've already taken the first step. Good luck!

In Flex, how can I get the dimensions of a childless canvas component at runtime?

One of my components looks like this:
<mx:Canvas id="grid" width="100%" height="100%"></mx:Canvas>
On creationComplete, I load some spirte that I want to scale and position based on the dimensions of the canvas to create a custom grid layout, but when I access the dimensions of 'grid' I get 0 and 0. Is there any way to get the dimensions without assigning absolute values?
I can't check this at the moment but can you access the measuredHeight and measuredWidth?
My understanding is that unless the Canvas contains one or more DisplayObject children, it will always report its width and height properties as 0, regardless of the percentage sizings you may have applied to it.
You could always add an empty dummy DisplayObject to the Canvas, but that wouldn't be very elegant. Depending on how you've planned to implement your custom grid, it's possible you'll have to rethink the design...
Is it possibly created but not yet displayed (e.g. visible)? Since final size and shape is derived, it doesn't happen until the thing actually needs to be drawn. Width and height are documented to be the values actually in use - there are even events for when they change.
Worst case, try trapping it out in the canvas Resize event.
have you tried binding the width and height of the Canvas to its parent? If it is 100%, than it will have the same size as its parent and you could either bind or size your Sprite (UIComponent) based on the parent container of the Canvas.

How do I enable autoresizing for a Flex UIComponent?

I have a class which extends UIComponent and draws directly onto a Sprite contained within. Currently I'm (probably incorrectly) listening to the Event.RESIZE event and drawing the contents when the width and height are non-zero. The problem is that even though I've passed percentage widths to the instance tag, it doesn't appear to be resized along with other Flex components on the page, certainly the resize event isn't being fired at all.
I've hacked it for the moment by binding the width and height to a container which does resize, but how should I really be handling this?
Update :
It turns out I was setting the width and height somewhere in the redraw method (I have no recollection of why I did this!). I shall go hang my head in shame now...
I think you need to provide more information. I'm doing exactly the same, and it works smoothly for me. Perhaps the answer lies somewhere else: e.g. exactly what type of container do you use? Isn't it possible that the space gained/lost on resizing gets allocated to some other component within the cointainer? Try substituting your own component with an mx:Box with some colored background, and see if that resizes with the container.

Resources