Flex: первые шаги

Даже не знаю с чего начать, в общем пока суть до дело и у меня нет реального проекта, посадили мну учить Flex. Не то что бы я был против, но некоторые моменты очень сильно харили. То есть как — привык я значит что в HTML можно любой объект закастомайзить через CSS, надо только написать что-то типа:


// для ячейки
td.class {
    background-color:#ffffff;
    border-color:#000000;
    vertical-align:middle;
}
// или для дива
div.class {
    background-color:#ffffff;
    border-color:#000000;
    height:50px;
    line-height:50px;
}

А во флексе так не получается, не все компоненты поддерживают background-color, border-color и уж тем более vertical-align. А если делаешь свой компонент на основе UIComponent то уж тем более половина свойств не реализована. Вот собственно это я и решил поправить, написав промежуточный (абстрактный) класс, а написав поделится с вами.

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


package ua.kiev.mabp{

import mx.controls.Label;
import mx.controls.Text;
import mx.core.UIComponent;
import mx.core.UITextField;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;

public class MyComponent extends UIComponent {

    /**
     * Статически сетим в StyleManager новый стиль
     */
    private static var classConstructed:Boolean = classConstruct();

    /**
     * Флаги устанавливается когда меняются CSS-свойства
     */
    private var verticalAlignChanged:Boolean = true;
    private var backgroundStypePropChanged:Boolean = true;
    private var borderStypePropChanged:Boolean = true;

    private var textChanged:Boolean = false;
    private var _textField:UITextField;
    /**
     * Сохранять текст отдельно нужнно потому что
     * когда он сетится _textField еще не создан
     */
    private var _text:String;

    /**
     * Все UI компоненты должны иметь только один конструктор, без параметров
     */
    public function MyComponent() {
        super();
    }

    /**
     * Геттер
     * @return текст лейбы
     */
    public function get text():String {
        return _text;
    }

    /**
     * Сеттер
     * @param text текст лейбы
     */
    public function set text(text:String):void {
        _text = text;
        textChanged = true;
        invalidateProperties();
    }

    /**
     * Если текст лейбы поменялся меняем его
     */
    override protected function commitProperties():void {
        super.commitProperties();
        if (textChanged) {
            textChanged = false;
            _textField.text = _text;
        }
    }

    /**
     * Добавляет значение по умолчанию для нового свойства в StyleManager
     * @return true
     */
    private static function classConstruct():Boolean {
        var declaration:CSSStyleDeclaration = StyleManager.getStyleDeclaration("MyComponent");
        if (declaration) {
            if (declaration.getStyle("verticalAlign") == undefined)
                declaration.setStyle("verticalAlign", "top");
            if (declaration.getStyle("backgroundColor") == undefined)
                declaration.setStyle("backgroundColor", 0xffffff);
            if (declaration.getStyle("borderColor") == undefined)
                declaration.setStyle("borderColor", 0x000000);
        } else {
            declaration = new CSSStyleDeclaration();
            declaration.defaultFactory = function():void {
                this.verticalAlign = "top";
                this.backgroundColor = 0xffffff;
                this.borderColor = 0x000000;
            };
            StyleManager.setStyleDeclaration("MyComponent", declaration, true);
        }

        return true;
    }

    /**
     * Создает текст, почти как в Label
     */
    override protected function createChildren():void {
        super.createChildren();

        if (!_textField) {
            _textField = new UITextField();
            _textField.text = _text;
            addChild(_textField);
        }
    }

    /**
     * Проверяет извененное свойство, если оно кастомное
     * то ставится флаг что его надо перерисовать
     * @param styleProp
     */
    override public function styleChanged(styleProp:String):void {
        super.styleChanged(styleProp);
        if (styleProp == "verticalAlign") {
            verticalAlignChanged = true;
            invalidateDisplayList();
        }
        if (styleProp == "backgroundColor") {
            backgroundStypePropChanged = true;
            invalidateDisplayList();
        }
        if (styleProp == "borderColor") {
            borderStypePropChanged = true;
            invalidateDisplayList();
        }
    }

    /**
     * Перерисовывает элемент если был установлен флаг
     * @param unscaledWidth реальная ширина
     * @param unscaledHeight реальная высота
     */
    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
        super.updateDisplayList(unscaledWidth, unscaledHeight);

        if (verticalAlignChanged) {
            var verticalAlign:String = getStyle("verticalAlign");
            var fontSize:Number = _textField.getStyle("fontSize");
            var verticalGap:Number = _textField.getStyle("verticalGap");
            if (verticalAlign == "middle") {
                _textField.y = (height - fontSize - verticalGap) / 2;
            } else if (verticalAlign == "bottom") {
                _textField.y = height - fontSize - verticalGap / 2;
            }
            verticalAlignChanged = false;
        }

        if (borderStypePropChanged) {
            graphics.lineStyle(1, getStyle("borderColor"), 1);
            borderStypePropChanged = false;
        }

        if (backgroundStypePropChanged) {
            graphics.beginFill(getStyle("backgroundColor"));
            graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
            graphics.endFill();
            backgroundStypePropChanged = false;
        }

    }
}
}

Тут все просто, только ширина бордера будет всегда один пиксель, для того чтобы ее изменить надо будет реализовать свойство borderWidth и размер шрифта не меняется, ну вобщем будет нужда — доделаю а пока просто как примерчик для вас и напоминалка для меня

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


<?xml version="1.0" ?>
<mx:Application
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        paddingBottom="50"
        paddingTop="50"
        paddingLeft="50"
        paddingRight="50"
        xmlns:local="ua.kiev.mabp.*">

    <local:MyComponent id="myComponent" text="my label text" height="50" width="100"/>
    <mx:Button label="click me" click="onClick()"/>

    <mx:Script>
        public function onClick():void {
            myComponent.text = "text changed";
        }
    </mx:Script>

    <mx:Style>
        MyComponent {
            background-color: #ffffff;
            border-color: #000000;
            vertical-align: middle;
            text-align: center;
        }
    </mx:Style>
</mx:Application>

2 Комментарии “Flex: первые шаги

  1. Прикольно, много кода непонятого. Можешь пример поинтереснее составить? Хоть какой-то экшен

Комментарии закрыты