PDA

Просмотр полной версии : Mobile TextInput skin + embed images


djyamato
11.02.2014, 00:31
Здравствуйте
Попытался сделать скин для TextInpot для мобилок
В зависимости от типа поля ввода и от разрешения в скине слева от textDisplay должна быть иконка (силуэт, липа, замочек итд).
Embed всех этих картинок я делаю в скине.
Правильно ли это ?
"Приэмбедятся" к проекту они один раз ? Не столько раз сколько скин используется ?

Также прошу указать на ошибки если не сложно.
component

package components
{
import spark.components.TextInput;

public class CustomTextInput extends spark.components.TextInput
{
protected var _type:String;

[Bindable]
public function CustomTextInput()
{
super();
}

public function get type():String
{
return _type;
}
public function set type(value:String):void
{
_type = value;
}
}
}


skin

package components.skins
{
import avmplus.getQualifiedClassName;

import components.CustomTextInput;

import flash.display.Bitmap;
import flash.events.Event;
import flash.events.TextEvent;
import flash.system.Capabilities;
import flash.text.TextFormat;
import flash.utils.getDefinitionByName;

import mx.core.FlexGlobals;

import spark.primitives.BitmapImage;
import spark.skins.mobile.TextInputSkin;

public class TextInputSkin extends spark.skins.mobile.TextInputSkin
{
protected var _iconImage:Bitmap;

[Embed(source="assets/lock_160.png")]
protected var lockClass_160:Class;

[Embed(source="assets/lock_240.png")]
protected var lockClass_240:Class;

[Embed(source="assets/lock_320.png")]
protected var lockClass_320:Class;

[Embed(source="assets/person_160.png")]
protected var personClass_160:Class;

[Embed(source="assets/person_240.png")]
protected var personClass_240:Class;

[Embed(source="assets/person_320.png")]
protected var personClass_320:Class;

[Embed(source="assets/search_160.png")]
protected var searchClass_160:Class;

[Embed(source="assets/search_240.png")]
protected var searchClass_240:Class;

[Embed(source="assets/search_320.png")]
protected var searchClass_320:Class;

protected var _paddingLeft:int = 15;

protected var _fontSize:int = 14;

public function TextInputSkin()
{
super();
}

override protected function createChildren():void
{
super.createChildren();
_iconImage = new Bitmap();
addChild(_iconImage);
textDisplay.setStyle("fontStyle","italic");
//textDisplay.addEventListener(TextEvent.TEXT_INPUT, textInputHandler);
}

protected function textInputHandler(event:TextEvent):void
{
//hostComponent.setStyle("fontSize",_fontSize);
}

override protected function commitProperties():void
{
super.commitProperties();

try
{
switch((hostComponent as CustomTextInput).type)
{
case "password":

switch(applicationDPI)
{
case 320:
_iconImage.bitmapData = (new lockClass_320 as Bitmap).bitmapData;
break;
case 240:
_iconImage.bitmapData = (new lockClass_240 as Bitmap).bitmapData;
break;
case 160:
_iconImage.bitmapData = (new lockClass_160 as Bitmap).bitmapData;
break;
}
break;
case "personal":

switch(applicationDPI)
{
case 320:
_iconImage.bitmapData = (new personClass_320 as Bitmap).bitmapData;
break;
case 240:
_iconImage.bitmapData = (new personClass_240 as Bitmap).bitmapData;
break;
case 160:
_iconImage.bitmapData = (new personClass_160 as Bitmap).bitmapData;
break;
}
break;
case "search":
switch(applicationDPI)
{
case 320:
_iconImage.bitmapData = (new searchClass_320 as Bitmap).bitmapData;
break;
case 240:
_iconImage.bitmapData = (new searchClass_240 as Bitmap).bitmapData;
break;
case 160:
_iconImage.bitmapData = (new searchClass_160 as Bitmap).bitmapData;
break;
}

break;
}
_iconImage.smoothing=true;
textDisplay.setLayoutBoundsPosition(_iconImage.width+_paddingLeft*2, textDisplay.getLayoutBoundsY());
promptDisplay.setLayoutBoundsPosition(_iconImage.width+_paddingLeft*2, promptDisplay.getLayoutBoundsY());
promptDisplay.setStyle("fontStyle","italic");
}
catch(error:Error)
{
trace(error.message);
}

setFontSize();
}

private function setFontSize():void
{
switch(applicationDPI)
{
case 320:
_fontSize=36;
break;
case 240:
_fontSize=28;
break;
case 160:
_fontSize=18;
break;
}
hostComponent.setStyle("fontSize",_fontSize);
}

override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
{
super.layoutContents(unscaledWidth, unscaledHeight);

setFontSize()

setElementPosition(_iconImage, _paddingLeft, (measuredHeight-_iconImage.height)/2);

// сдвиг всей конструкции вправо от иконки
setElementPosition(textDisplay, _iconImage.width+_paddingLeft*2, textDisplay.getLayoutBoundsY());

try
{
setElementPosition(promptDisplay, _iconImage.width+_paddingLeft*2, promptDisplay.getLayoutBoundsY());
promptDisplay.setStyle("fontStyle","italic");
}
catch(error:Error)
{

}

invalidateDisplayList();
validateNow();
}
}
}


использование

<components:CustomTextInput id="ti1"
prompt="password here"
displayAsPassword="true"
borderVisible="false"
contentBackgroundAlpha="0"
type="password"
focusAlpha="0"
color="0x434343"
skinClass="components.skins.TextInputSkin"/>

alatar
12.02.2014, 16:30
"Приэмбедятся" к проекту они один раз ? Не столько раз сколько скин используется ?
Один.
Также прошу указать на ошибки если не сложно.
Вот этим вы что пытались сделать?
[Bindable]
public function CustomTextInput()
{
super();
}
Так не делается (http://help.adobe.com/ru_RU/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7cc5.html).

Где инвалидация?
public function set type(value:String):void
{
_type = value;
}
Судя по коду скина, вы должны были тут установить флаг, что тип поменялся и вызвать invalidateProperties(). А вообще вы должны были вызвать (после приведения скина в порядок) дополнительно invalidateSize() (у вас меняются расчетные размеры и их необходимо пересчитать) и invalidateDisplayList().

Зачем try в commitProperties? Достаточно проверить, что компоненты существуют.
commitProperties вызывается по многим причинам, поэтому в этой функции (зачастую. и это ваш случай) необходимо проверять, а изменение вашего ли свойства вызвало commitProperties.

Зачем вы в commitProperties вмешиваетесь в layout?

Зачем вызывается invalidateDisplayList в layoutContents? layoutContents вызывается в функции updateDisplayList, а вы тут же вызываете ее еще раз.

где переопределение measure?

P.S. Иконки можно было и в стили вынести, хоть и не обязательно.

djyamato
12.02.2014, 19:09
Отличный ответ, спасибо большое.
Есть вопросы:
Зачем переопределять measure ?
Если не в commitProperties вмешиваться в layout, то где ? В переопределенном measure ?

А вообще вы должны были вызвать (после приведения скина в порядок) дополнительно invalidateSize() (у вас меняются расчетные размеры и их необходимо пересчитать) и invalidateDisplayList().

Из какого места вызвать ?

alatar
12.02.2014, 19:48
Зачем переопределять measure ?
Для расчета размера по-умолчанию. Сейчас он рассчитывается без учета иконки (см. исходники TextInputSkin).
Если не в commitProperties вмешиваться в layout, то где ?
Может это прозвучит для вас странно, но в layoutContents.
Из какого места вызвать ?

type должен был бы выглядеть как-то так:

//ваше значение по-умолчанию
//none или null у вас вообще никак не обрабатываются
protected var _type:String = "none";

//а так ли вам нужен binding для этого свойства?
[Bindable(event="typeChange")]
public function get type():String
{
return _type;
}
public function set type(value:String):void
{
if (_type == value)
return;

_type = value;

invalidateSize();
invalidateProperties();
invalidateDisplayList();

dispatchEvent("typeChange");
}