Flex. Понимание itemRenderer'ов. Часть 5. Эффективность

Часть 5. Эффективность

Если Вы отображаете большое количество itemRenderer'ов, в DataGrid или в AdvancedDataGrid, производительность Вашего приложения может быть неблагоприятной, если Вы не кодируете эти itemRenderer'ы эффективно. Вот некоторые советы, которые могли бы помочь:

Переключаемые стили

Вот itemRenderer, который переключает компоненты в зависимости от значения поля данных.

<mx:Canvas>
    <mx:Script>
        <![CDATA
           private function lessThanZero():Boolean {
               return data.price < 0;
           }
        ]]>
    </mx:Script>
    <mx:Label text="{data.price}" color="#FF0000" visible="{lessThanZero()}"/>
    <mx:Label text="{data.price}" color="#00FF00" visible="{!lessThanZero()}"/>
</mx:Canvas>

Это будет быстрее чем установка стиля. Некоторые другие вещи, чтобы иметь в виду:

Расширенный UIComponent

Безусловно самый эффективный способ написать itemRenderer состоит в том, чтобы расширить UIComponent использующий класс ActionScript. У Вас будет полный контроль над кодом, и рендерер будет настолько эффективен насколько возможно.

Возьмём начало из примера выше, переключающиеся стили, и напишем простой itemRenderer, расширяющий UIComponent.

package renderers
{
    import mx.controls.listClasses.IListItemRenderer;
    import mx.core.UIComponent;
 
    public class PriceItemRenderer extends UIComponent implements IListItemRenderer
    {
        public function PriceItemRenderer()
        {
            super();
        }
    }
}

Обратите внимание, что мало того, что я написал класс, чтобы расширить UIComponent, у меня также есть исполняющий интерфейс IListItemRenderer. Это необходимо сделать, потому что контрол List будет ожидать, что любой рендерер осуществит этот интерфейс, и если Вы этого не сделаете, то Вы получите ошибку во время выполнения программы, поскольку список пытается привести рендерер к этому интерфейсу.

Если Вы прочитаете документацию по IListItemRenderer, то Вы увидите, что он - объединение многих других интерфейсов, большинство которых UIComponent осуществляет для Вас. Но есть один интерфейс, расширенный IListItemRenderer'ом, который UIComponent не осуществляет: IDataRenderer. Это требует, чтобы Вы добавили код, чтобы дать классу itemRenderer свойство data, которое Вы использовали всё время.

Если Вы попытаетесь использовать этот класс, не осуществляя IDataRenderer, то Вы получите эти ошибки, когда Вы компилируете код:

Отредактируйте этот класс и измените его на следующее:

package renderers
{
    import mx.controls.listClasses.IListItemRenderer;
    import mx.core.UIComponent;
    import mx.events.FlexEvent;

    public class PriceItemRenderer extends UIComponent implements IListItemRenderer
    {
        public function PriceItemRenderer()
        {
            super();
        }

        // Internal variable for the property value.
        private var _data:Object;

        // Make the data property bindable.
        [Bindable("dataChange")]

        // Define the getter method.
        public function get data():Object
        {
            return _data;
        }

        // Define the setter method, and dispatch an event when the property
        // changes to support data binding.
        public function set data(value:Object):void
        {
            _data = value;
            dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
        }
    }
}

Я взял код непосредственно из документации по Flex для IDataRenderer, таким образом Вы можете не набирать его непосредственно.

Попутно, Вы можете добавить в двух метках.

  1. Добавить переменные для удержания двух меток.
    private var posLabel:Label; private var negLabel:Label;
    
  2. Модифицировать функцию set data для вызова invalidateProperties(). Это важно, потому что изменение данных должно изменить текст в метках И их видимость.
        public function set data(value:Object):void {
            _data = value;
            invalidateProperties();
            dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
        }
    

    Вызов invalidateProperties() говорит Flex-фреймворку вызывать функциею commitProperties() в подходящее время.

  3. Перегрузите createChildren() и создайте метки, добавляя их к отображаемому списку компонента. Обратите внимание, что в дополнение к созданию меток, их стили и свойства visible также установлены.
    override protected function createChildren():void
    {
        super.createChildren();
        posLabel = new Label();
        posLabel.visible = false;
        posLabel.setStyle("color",0x00FF00);
        addChild(posLabel);
        negLabel = new Label();
        negLabel.visible = false;
        negLabel.setStyle("color",0xFF0000);
        addChild(negLabel);
    }
    
  4. Перегрузите commitProperties(), чтобы установить текст меток и их видимость. В прошлом Вы перегружали set data, чтобы сделать этот тип изменения, и, если Вы предпочитаете, Вы также можете сделать это в этом классе.
    override protected function commitProperties():void           
    {
        super.commitProperties();
        posLabel.text = data.price;
        negLabel.text = data.price;
        posLabel.visible = Number(data.price) > 0;
        negLabel.visible = Number(data.price) < 0;
    }
    
  5. Перегрузите updateDisplayList(), чтобы изменить размеры и позиции меток. Вы должны изменить размер меток, потому что их заданный по умолчанию размер - 0X0. Это - другая вещь, которую класс Container сделает для Вас. Так как это довольно простой itemRenderer, Вы можете только задать размер меток, чтобы соответствовать размеру itemRenderer.
    override protected function updateDisplayList(
    unscaledWidth:Number,unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        posLabel.move(0,0);
        posLabel.setActualSize(unscaledWidth,unscaledHeight);
        negLabel.move(0,0);
        negLabel.setActualSize(unscaledWidth, unscaledHeight);
    }
    

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

Примечания к UIComponent

Класс UIComponent это основа для всех визуальных компонентов Flex - контролов и контейнеров. Вот некоторые советы об использовании UIComponent в роли Вашего itemRenderer'а.