Путь скинизации посредством css тернист и многотруден. Особенно если каждый стиль требуют собственных скинов для виджетов (иконок, кнопок и т.д). Предположим нам надо подгрузить картинку. Для примера создадим класс наследованный от UIComponent и требующий подгрузки картинки описанной в css. Назовем класс Example.as.
Стили для него описаны в одноименном блоке стиля. (вы разумеется знаете, что стили цепляются к одноименной компоненте автоматом и не требуют каких-то дополнительных директив?)
Казалось бы чего проще?…
XML:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:ns1="src.*"> | |
<!−− так конечно делать не надо, но для примера покатит :) с css будет так же!−−> | |
<mx:Style> | |
Example{image: Embed("graphics/image.png");} | |
</mx:Style> | |
<ns1:Example x="42" y="24"/> | |
</ns1:Example></mx:Application> |
- package src
- {
- import mx.core.UIComponent;
- import mx.controls.Image;
- public class Example extends UIComponent
- {
- private var image: Image;
- public function Example()
- {
- }
- override protected function createChildren(): void
- {
- super.createChildren();
- image=new Image();
- image.source=getStyle("image");
- addChild(image);
- }
- }
- }
И после компиляции картинку благополучно не видим. Почему? Потому, что по умолчанию ее размеры составляют 0 x 0. Для того чтобы она отобразилась корректно требуется задать ей реальные размеры, каковые нам любезно предоставляют свойства measuredWidth и measuredHeight. Однако актуальные значения ширины и высоты будут доступны только после вызова метода protected function measure(): void UIComponent, о котором доступна подробная информация в хелпе.
Ну и собственно результат:
- package src
- {
- import mx.core.UIComponent;
- import mx.controls.Image;
- public class Example extends UIComponent
- {
- private var image: Image;
- public function Example()
- {
- }
- override protected function createChildren(): void
- {
- super.createChildren();
- image=new Image();
- image.source=getStyle("image");
- addChild(image);
- }
- override protected function measure():void
- {
- super.measure();
- image.setActualSize(image.measuredWidth, image.measuredHeight);
- }
- }
Следует отметить, что подобных проблем с размерами не возникает в mxml-e.
По ряду причин была вынуждена установить на свою рабочую машину Vista. Расскажу о тех проблемах, с которыми столкнулась в ходе установки flex builder2 под Vista. Сразу оговорюсь переходить на 3-й builder мы не стали т.к он бета и показался нам не стабильным.
Проблема раз. Попытка установить второй билдер под eclipse 3.3:

Проблема два. Вернее легкое неудобство. В процессе установки инсталятор отказался демонстрировать контролы. Просто не отображал. Устанавливать пришлось на автопилоте руководствуясь подсознанием. Установила. Честно признаюсь не с первого раза.
Update установила.
Проблема три. SVN отказался дружить с подцепленым проектом. Проблема довольно специфическая, врядли у кого-то повторится, поэтому подробно останавливаться на ней не буду. Починила.
Установила subclips.
Последняя капля. Эклипс периодически вылетал с предупреждением следующего вида

В debugg-режиме с прерываниями он вылетал постоянно. Переставляла builder и java. Не помогло.
При большом количестве меток (да и вообще компонент) и частой их отрисовке вы непременно столкнетесь с тормозами. В случае с метками есть альтернатива в лице mx.core.UITextField, которой и посвящен этот пост. Что нас привлекает в mx.controls.Label? Возможность отобразить некий текст и применить к нему стили. UITextField нам эти возможности предоставляет так же. Однако есть одна тонкость. Как работать со стилями если:
public function setStyle(styleProp:String, value:*):void - Does nothing. A UITextField cannot have inline styles.
Не очень понятно зачем вообще нужен этот метод если он ничего не делает. Была мысль, что он описан в каком-то из имплементящихся интерфейсов, но подтверждения этому в коде найти не удалось. Впрочем я отвлеклась. Ну так как же работать со стилями? Да в общем точно так же, только через свойство styleName.
styleName:Object [read-write] - The class style used by this component. This can be a String, CSSStyleDeclaration or an IStyleClient.
Т.е uiTextField.styleName.setStyle("color", 0xff0000); сработает, но только если к UITextField уже был применен какой-то стиль. Не поленилась написать небольшой пример:
XML:
<?xml version="1.0" encoding="utf-8"?> | |
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> | |
<mx:Script> | |
<![CDATA[ | |
import mx.core.UITextField; | |
import mx.styles.*; | |
| |
private var uiTextField: UITextField; | |
| |
override protected function createChildren(): void | |
{ | |
super.createChildren(); | |
uiTextField=new UITextField(); | |
addChild(uiTextField); | |
uiTextField.text="mx.core.UITextField"; | |
trace("uiTextField.styleName: "+uiTextField.styleName); | |
// uiTextField.styleName: null | |
var styleCss:CSSStyleDeclaration = new CSSStyleDeclaration(); | |
styleCss.setStyle('fontSize', 15); | |
styleCss.setStyle('color', picker.selectedColor); | |
uiTextField.styleName=styleCss; | |
} | |
| |
public function changeColor(): void | |
{ | |
uiTextField.styleName.setStyle("color", picker.selectedColor); | |
} | |
| |
]]> | |
</mx:Script> | |
<mx:ColorPicker id="picker" change="changeColor()" /> | |
</mx:Application> |
В одном из предыдущих постов я рассказывала о решении проблемы пропадающих DataTip-ов в LineSeries с нефильтрованными данными (т.е filterData=false).
Как я уже говорила проблема в строке 969 класса mx.charts.series.LineSeries.as:
if (!isNaN(v.yFilter) && !isNaN(v.xFilter))
Не буду приводить исходный код тут. Слишком много букв.
При наследовании мне пришлось не только переопределить findDataPoints, но и воспроизвести приватный метод серии formatDataTip. Фактически же изменения коснулись только findDataPoints. Я добавила ряд проверок, однако оказалось что это был не лучший выход. Здесь народ столкнулся с аналогичной проблемой и нашел гораздо более удачное, на мой взгляд, решение. В findDataPoints они избежали многочисленных проверок заменив вышеупомянутую строку
if (!isNaN(v.yFilter) && !isNaN(v.xFilter)) на
if (!isNaN(v.yNumber) && !isNaN(v.xNumber)).
В процессе работы над очередным проектом у нас с Junik возникла потребность в использовании каскадных стилей. Подробнее о стилях и вариантах их использования написано тут, методика подгрузки css в рантайме тут, здесь же речь пойдет о тех проблемах с которыми мы столкнулись в процессе подгрузки файла css на стадии компиляции.
В окне свойств каждого проекта есть вкладка именуемая Flex Compiler, где в строке additional compiller arguments можно задавать опции для компиляции приложения. В перечне присутствует такая незаменимая в нашем случае опция как defaults-css-url. Собственно эту, как и все остальные, опцию можно вынести и в специальный конфигурационный xml. Хотя сейчас не об этом. Сейчас о том, что где бы вы ни задали ваш css вовсе не факт что он у вас заработает. Нам как раз посчастливилось столкнуться с этой проблемой. Изначально наш css подгружался в mxml-ине посредством тега Style и все прекрасно работало. После того как мы вынесли css в конфигурационный файл приложение работать напрочь отказывалось и постоянно генерило ошибки в рантайме.
В хелпе ничего внятного мы не нашли. Нечто отдаленное покоится тут Активное прогугливание ответов на вопрос “что за фиг?!” тоже нам не доло. Кроме криков о помощи еще кучки товарищей различных национальностей гугл ничем не порадовал.
Пришлось думать самим. Суть проблемы на поверку оказалась в следующем:
Как вы вероятно знаете, по умолчанию флекс пользуется услугами default.css. (у меня c:\Program Files\Adobe\Flex Builder 2\Flex SDK 2\frameworks\defaults.css) в котором аккуратно прописывает все стили компонент. Когда вы подгружаете css в теге Style приложение первоначально грузит вышеупомянутый defaults.css и только после этого применяет к приложению правила из вашего css. В случает же когда вы прописываете defaults-css-url defaults.css замещается вашим файлом и приложению просто не хватает стилей для отображения.
При работе с чартингом, одной из осей которого является DateTimeAxis, часто возникает потребность в изменении формата отображения меток. Как я поняла в ходе общения с кодом DateTimeAxis, сам флекс не меняет формат даты в зависимости от локали. По умолчания дата отображается в формате m/d/yy. Для российского глаза такое отображение несколько непривычно. Хелп предоставляет два пути решения этой проблемы.
1. labelFunction:Function [read-write]
Called to format axis values for display as labels. A labelFunction has the following signature:
- function labelFunction(labelValue:Object, previousValue:Object, axis:IAxis):String
If you know the types of the data your function will be formatting, you can specify an explicit type for the labelValue and previousValue parameters.
Казалось бы вот оно счастье, однако поспешность в выборе может послужить для вас причиной дополнительного геморроя. Качественная замена функции дело довольно муторное. Ведь интервал между метками может составлять как секунды так и годы. Куча кода. Рекомендую с негодованием отвергнуть эту веселую перспективу и обратить свой взор к пункту 2.
2. В хелпе есть такое понятие как Protected Methods. Для человека пришедшего из AS2 и не озаботившегося ознакомлением с матчастью AS3 такое буквосочетание может показаться слабо информативным, однако белые люди сжевавшие в процессе общения с флексом уже не одну pdf-ную страницу в курсе что Protected Methods - методы класса которые можно переопределять в наследниках. Часто большинство этих методов скрыто в недрах хелпа в аккордеоне с надписью “Show Inherited Protected Methods", однако это не наш случай. Интересующие нас сейчас методы DateTimeAxis на виду:
- formatDays(d:Date, previousValue:Date, axis:DateTimeAxis):String
- formatMilliseconds(d:Date, previousValue:Date, axis:DateTimeAxis):String
- formatMinutes(d:Date, previousValue:Date, axis:DateTimeAxis):String
- formatMonths(d:Date, previousValue:Date, axis:DateTimeAxis):String
- formatSeconds(d:Date, previousValue:Date, axis:DateTimeAxis):String
- formatYears(d:Date, previousValue:Date, axis:DateTimeAxis):String
Разумеется прежде чем переопределять их в соответствии с вашими пожеланиями следует ознакомиться с исходным кодом DateTimeAxis. Там за вас уже все придумали и написали:
- protected function formatYears(d:Date, previousValue:Date, axis:DateTimeAxis):String
- {
- var fy:Number = d[fullYearP];
- return fy.toString();
- }
- protected function formatMonths(d:Date, previousValue:Date, axis:DateTimeAxis):String
- {
- var fy:Number = d[fullYearP];
- return (d[monthP] + 1) + "/" + ((fy % 100) < 10 ? "0" + fy % 100 : fy % 100);
- }
- protected function formatDays(d:Date, previousValue:Date, axis:DateTimeAxis):String
- {
- var fy:Number = d[fullYearP];
- return (d[monthP] + 1) + "/" + d[dateP] + "/" + ((fy % 100) < 10 ? "0" + fy % 100 : fy % 100);
- }
- protected function formatMinutes(d:Date, previousValue:Date, axis:DateTimeAxis):String
- {
- return d[hoursP] + ":" + (d[minutesP] < 10 ? "0" + d[minutesP] : d[minutesP]);
- }
- protected function formatSeconds(d:Date, previousValue:Date, axis:DateTimeAxis):String
- {
- return d[hoursP]+ ":" + (d[minutesP] < 10 ? "0" + d[minutesP] : d[minutesP]) + ":" + (d[secondsP] < 10 ? "0" + d[secondsP] : d[secondsP]);
- }
Потребуется только слегка откорректировать эти методы в соответствии с вашими пожеланиями. Или, если приложение требует некоторой гибкости, добавить к уже имеющемуся формату еще несколько форматов отображения. (в зависимости от локали)
Кстати. Если вдруг получившиеся в ходе переопределения методов метки будут натыкаться друг на друга и делать подписи абсолютно нечитаемыми следует воспользоваться методом reduceLabels(intervalStart:AxisLabel, intervalEnd:AxisLabel):AxisLabelSet, а никак не свойством interval : Number, как это может захотеться с первого взгляда. Но это уже совсем другая история…
10> 10> 10>
Flex Stress Testing Framework
The information in this article can help you start load testing your own Flex Data Services applications.
Ранее я упоминала о том, что в LineChart с не фильтрованными данными отказываются демонстрироваться DataTips. Эту странность я склонна классифицировать как баг, поскольку с другими чартами такой проблемы у меня не возникло.
Суть проблемы:
При наведении мыши на рабочую область чартинга вызывается метод findDataPoints(x:Number,y:Number,sensitivity:Number):Array mx.charts.series.LineSeries, который проверяет с погрешностью sensitivity соответствие точки mouseX,mouseY пикам серии.
- var v:LineSeriesItem = _renderData.filteredCache[cur];
- if (!isNaN(v.yFilter) && !isNaN(v.xFilter))
- {
- var dist:Number = (v.x - x)*(v.x - x) + (v.y - y)*(v.y -y);
- if (dist <= minDist2)
- {
- minDist2 = dist;
- minItem = v;
- }
- }
в строке if (!isNaN(v.yFilter) && !isNaN(v.xFilter)) на isNaN проверяются значения свойств, которые просто не создаются в случае, когда filterData=false. Происходит это в методе updateFilter():void того же LineSeries.
Решение:
Наследуем LineSeriesNew от LineSeries, в котором и переопределяем метод findDataPoints
- trace("0.16+41.83="+(0.16+41.83));
выводит
0.16+41.83=41.989999999999995
сааабж… (уважительно)
:: Следующие >>
