Создание компонентов Flex из XML - PullRequest
1 голос
/ 04 февраля 2010

У меня есть XML, и у него есть опция атрибута или поле со списком, анализирующий, что мне нужно для динамического создания компонентов в моем flex.

Viatropos дал замечательный код, но я не могу его выполнить ... может кто-нибудь произвести его ... спасибо

Ответы [ 2 ]

10 голосов
/ 04 февраля 2010

Вы можете динамически создавать компоненты во Flex с помощью чего-то подобного:

Пример данных

<?xml version="1.0" encoding="UTF-8"?>
<components type="array">
    <component type="mx.controls.ComboBox">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">0xff0000</color>
        <prompt>Im a Combo Box!</prompt>
    </component>
    <component type="mx.controls.Button">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">0xff0000</color>
        <label>Im a Button!</label>
    </component>
</components>

Пример приложения :

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    creationComplete="creationCompleteHandler()">

    <mx:Script>
        <![CDATA[

            import flash.display.DisplayObject;
            import mx.core.UIComponent;
            import mx.controls.ComboBox; ComboBox;

            protected function creationCompleteHandler():void
            {
                var components:Array = getComponentsFromXML(xml.component);
                var i:int = 0;
                var n:int = components.length;
                for (i; i < n; i++)
                {
                    panel.addChild(components[i] as DisplayObject);
                }
            }

            /**
             *  Parses an XML string, returns array of new components.
             */
            public function getComponentsFromXML(components:XMLList):Array
            {
                var result:Array = [];
                var child:Object;
                var component:UIComponent;
                var type:String;
                var clazz:Class;
                var i:int = 0;
                var n:int = components.length();
                for (i; i < n; i++)
                {
                    child = components[i];
                    type = child.@type;
                    try {
                        clazz = flash.utils.getDefinitionByName(type) as Class;
                    } catch (error:ReferenceError) {
                        traceImportError(type);
                    }

                    component = new clazz(); // dynamic

                    var properties:XMLList = child.elements();
                    var property:XML;
                    var name:String;
                    var value:Object;

                    // for each child node
                    for each (property in properties)
                    {
                        name = property.localName();
                        value = property.toString();
                        // create a more generic method to convert
                        // strings to numbers and whatnot
                        // this is a regular expression matching any digit
                        // check out rubular.com
                        if (/\d+/.test(value.toString()))
                            value = Number(value);

                        if (property.attribute("isStyle") == "true")
                            component.setStyle(name, value);
                        else
                            component[name] = value;
                    }
                    result.push(component);
                }
                return result;
            }

            protected function traceImportError(type:String):void
            {
                trace("Please include the class '" + type + "' in the swf.");
                var names:Array = type.split(".");
                var last:String = names[names.length - 1];
                trace("import " + type + "; " + last + ";");
            }

        ]]>
    </mx:Script>

    <!-- sample data -->
    <mx:XML id="xml" source="components.xml" />

    <!-- sample container -->
    <mx:Panel id="panel" width="100%" height="100%"/>

</mx:Application>

Пока у вас есть определенная структура для вашего XML, вы можете создать XMLUtil для общей обработки xml (например, получения всех свойств или преобразования строк в их правильный тип) и класса ComponentManifest, который принимает файл XML и преобразовал его в компоненты.

Вам также необходимо убедиться, что все классы, определенные в XML, импортированы в swf, иначе это вызовет эту ошибку. Вы можете сделать это так:

import mx.controls.ComboBox; ComboBox;

Прямой импорт без этой секунды ComboBox не сделает этого.

Это должно помочь вам начать работу, заполните ее по мере необходимости!

Проверьте Rubular , чтобы возиться с Регулярными выражениями , если вы хотите иметь лучший / расширенный анализ значения xml:).

2 голосов
/ 15 февраля 2010

Вот модифицированная версия решения @ viatropos:

Пример данных:

<?xml version="1.0" encoding="UTF-8"?>
<components type="array">
    <component type="mx.controls::ComboBox">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">"0xff0000"</location>
        <label>"Im a Combo Box!"</label>
    </component>
    <component type="mx.controls::Button">
        <width>100</width>
        <height>100</height>
        <color isStyle="true">"0xff0000"</location>
        <label>"Im a Button!"</label>
    </component>
</components>

Здесь, очевидно, произошла ошибка, когда использовался для завершения тега.

Я также добавил кавычки вокруг всех строковых значений, чтобы их было легче идентифицировать.

Образец (псевдо) Метод: createComponentsFromXML(xml.components)

public function createComponentsFromXML(components:XMLList):void
{
    var child:Object;
    var component:UIComponent;
    var i:int = 0;
    var n:int = components.length();
    for (i; i < n; i++)
    {
        child = components[i];
        var clazz:Class = flash.utils.getDefinitionByName(child.@type);
        component = new clazz(); // dynamic
        var property:Object;
        var value:Object;
        var useIntVal:Boolean;
        var intVal:int;
        // for each child node
        for (property in child.children())
        {
            useIntVal = false;
            value = property.toString();
            if(!(value.substr(1, 2) == '"' AND value.substr(-1, value.length()) == '"')) {
                useIntVal = true;
                intVal = parseInt(value);
            }
            // button["width"] = 100;
            if (property.attribute("isStyle") == "true")
                if(useIntVal) {
                    component.setStyle(property.localName(), intVal);
                } else {
                    component.setStyle(property.localName(), value);
                }
            else {
                if(useIntVal) {
                    component[property.localName()] = intVal;
                } else {
                    component[property.localName()] = value;
                }
            }
        }
    }
}

Я реализовал преобразование в int, убедившись, что проверяю, должно ли свойство быть строкой или int.

PS: У меня сейчас не установлен Flex, поэтому вы можете найти несколько ошибок, которые вам нужно исправить.

В этом случае вы можете захотеть, чтобы ваш XML был таким:

<?xml version="1.0" encoding="UTF-8"?>
<components type="array">
    <component type="mx.controls::ComboBox">
        <properties>
            <width>100</width>
            <height>100</height>
            <color isStyle="true">"0xff0000"</location>
            <label>"Im a Combo Box!"</label>
        </properties>
    </component>
    <component type="mx.controls::Button">
        <properties>
            <width>100</width>
            <height>100</height>
            <color isStyle="true">"0xff0000"</location>
            <label>"Im a Button!"</label>
        </properties>
        <children>
            <!--other children here-->
        </children>
    </component>
</components>

Потому что я сомневаюсь, что вы можете многое сделать с одним уровнем вложения в аккордеон.

Я оставлю реализацию функции вам.

...