I want to make a custom container, usable in MXML like:
<local:MyContainer>
<s:Label/>
<s:Button/>
...
</local:MyContainer>
...but I'd like to be able to catch when the children are added so that I can control stuff like when & where they're added.
I tried overriding addChild(), addChildAt(),开发者_运维百科 addElement(), addElementAt(), (extending the Group class) but they only fire when you add elements specifically with those functions - the application launches and the label, button, etc, end up in MyContainer without calling these functions.
How do I control the addition of sub-components via MXML? Am I on the wrong track - should I be writing a custom layout and/or skin instead?
You could try to overwrite the setter of the mxmlContent-Array. Probably this is used instead of addChild()...
I just found out that this works and it might be helpful for you. It has a downside. The Designer will display an error message "Multiple sets of visual children have been specified for the tag".
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import avmplus.getQualifiedClassName;
import flash.utils.getDefinitionByName;
import mx.core.IVisualElement;
import mx.core.UIComponent;
import spark.layouts.BasicLayout;
import spark.layouts.VerticalLayout;
private var customMxmlContent : Array = null;
private var customInitializeDone : Boolean = false;
override public function set mxmlContent(value:Array) : void {
if(!customInitializeDone) {
// customInitializeDone == false:
// this is called when the elements that are defined in THIS
// mxml file are added to mxmlContent.
super.mxmlContent = value;
customInitializeDone = true;
} else {
// customInitializeDone:
// called when the elements from another mxmls file are added.
// Another file uses this component in this way:
/*
<views:RoundedGroup width="100%">
<views:layout>
<s:VerticalLayout/>
</views:layout>
<s:Button label="1234" />
<s:Button label="5678" />
</views:RoundedGroup>
*/
// Here it is redirected to the innerGroup
// if you do not do this, the content of THIS mxml file is
// replaced by the other content
for(var i:uint=0; i < value.length; i++) {
innerGroup.addElement(value[i] as IVisualElement);
}
}
// Reset the layout
if(this.layout != null) {
// find out the layout class that is applied to this
var layClass : Class = getDefinitionByName(getQualifiedClassName(this.layout)) as Class;
// and apply it to innerGroup instead
innerGroup.layout = new layClass();
// and reset the layout of this to a BasicLayout to get the Rect to the correct
// position and the innerGroup above the Rect
this.layout = new BasicLayout();
}
}
]]>
</fx:Script>
<s:Rect left="10" right="10" top="10" height="100%" radiusX="11" radiusY="11">
<s:fill>
<s:SolidColor color="0xB7C8A8" />
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0xABABAB" weight="1" />
</s:stroke>
</s:Rect>
<!-- Items are added within set mxmlContent to this VGroup container -->
<s:Group id="innerGroup" left="10" right="10" top="10" />
</s:Group>
精彩评论