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>
Свежие комментарии