Spark equivalent of DisplayObjectContainer.contains()
In halo containers you could use the DisplayObjectContainer.contains() method to check if an element is a child, grandchild, great grandchild, … of a given container. This method might not always work as you expect when called on a spark container because not every element in a spark container is a DisplayObject.
There is currently no equivalent method for spark containers. There is a feature request to add this method here: SDK-24203. Please vote on that issue if you would like to see it added. In the mean time I threw together a workaround by climbing up the IVisualElement.parent property.
public static function sparkContains(container:IVisualElementContainer, element:IVisualElement):Boolean { while (element) { if (element == container) { return true } if (element.parent is IVisualElement) { element = IVisualElement(element.parent); } else { return false; } } return false; }
If you want to check if an element is a direct child of a container (and not a grandchild, great grandchild, etc.) then you can compare the parent/owner property of the element to the container:
public static function simpleContainment(container:IVisualElementContainer, element:IVisualElement):Boolean { return (element.owner == container); }
Check out this blog post for more on the differences between parent and owner.
Here is a sample application that has a couple (simple) tests for these methods:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="runTest()"> <fx:Script> <![CDATA[ import mx.core.IVisualElement; import mx.core.IVisualElementContainer; public function runTest():void { // compare sparkContains() to contains() trace(sparkContains(sc1, sc2), hc1.contains(hc2), 'expecting true'); trace(sparkContains(sc1, sc3), hc1.contains(hc3), 'expecting true'); trace(sparkContains(sc1, sc4), hc1.contains(hc4), 'expecting true'); trace(sparkContains(sc1, sc1), hc1.contains(hc1), 'expecting true'); trace(sparkContains(sc2, sc1), hc2.contains(hc1), 'expecting false'); // test simpleContainment trace(simpleContainment(sc1, sc2), 'expecting true'); trace(simpleContainment(sc1, sc3), 'expecting false'); } public static function simpleContainment(container:IVisualElementContainer, element:IVisualElement):Boolean { return (element.owner == container); } public static function sparkContains(container:IVisualElementContainer, element:IVisualElement):Boolean { while (element) { if (element == container) { return true } if (element.parent is IVisualElement) { element = IVisualElement(element.parent); } else { return false; } } return false; } ]]> </fx:Script> <s:Group id="sc1"> <s:Group id="sc2"> <s:Group id="sc3"> <s:Rect id="sc4" /> </s:Group> </s:Group> </s:Group> <mx:Canvas id="hc1"> <mx:Canvas id="hc2"> <mx:Canvas id="hc3"> <mx:Button id="hc4" /> </mx:Canvas> </mx:Canvas> </mx:Canvas> </s:Application>
Note: This sample requires Flex SDK 4.0.0.12093 or higher. You can get the latest SDK builds from opensource.adobe.com.
“because not every child of a spark container is a DisplayObject.”
That line could be a little confusing for people. If its a child it has to be a DisplayObject. You talking specifically about visual elements, which cannot be a child, the child is its owner, where the info stored inside the element is actually drawn and displayed.
I agree though that the API for elements seems somewhat incomplete due to an extremely easy method that could be implements by Adobe.
@Tink – You’re right that was poorly worded. I updated it to read “because not every element in a spark container is a DisplayObject”. Thanks for pointing that out. One of these days I’ll get around to writing a post on an explanation of DisplayObject sharing in spark containers.
Thx for the Tip