Статьи

Введение в Flash Camo Часть 2

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

Давайте начнем.




Чтобы освежить нашу память, это конечный продукт, который мы собираемся создать. Это средство запуска сайта Bobble Person, которое я использую на http://jessefreeman.com .

1_bobblehead_preview

Я уже говорил о создании системы листов наклеек , но теперь мы собираемся воспользоваться собственной встроенной системой Flash Camo. Давайте поговорим о том, как декали работают в камуфляже.

Основной особенностью фреймворка является система DecalSheet (находится в пакете «camo.core.decal»); состоит из классов DecalSheetManager , DecalSheet и Decal . Концепция DecalSheet была вдохновлена ​​наклейками, которые вы получите с модельными самолетами. Каждый комплект модели будет содержать графические листы, и на каждом листе вы сможете снять наклейку и поместить ее на модель. Версия DecalSheet от Camo позволяет загружать внешние изображения, вырезать наклейки и оформлять ими ваше приложение.

Для этого шага вам понадобится Photoshop CS 3/4, чтобы открыть PSD. Вы можете скачать его здесь .

Как только вы загрузите PSD, откройте его и посмотрите.

2_bobble_head_skin

Как видите, у нас простой дизайн. Я пошел вперед и сделал всю подготовительную работу для вас, поэтому давайте просто перейдем к «сохранить как» и создадим новый PNG. Примечание: если вы перейдете в «Save For Web», вы увидите фрагменты, которые мы будем использовать позже в этом руководстве.

Мы сохраним этот png как «default.png» в нашей папке «html-template / images / skins» в нашем проекте BobbleHeadApp. Вы также можете щелкнуть правой кнопкой мыши на следующем изображении и использовать его вместо PSD. Убедитесь, что вы сохранили его как «default.png»

3_bobble_head_skin

Теперь, когда у нас есть наш скин, нам нужно создать Global DecalSheet Manager.

Наш сайт будет широко использовать систему DecalSheet, но сначала нам нужно найти способ сделать ее доступной для всего нашего приложения. Как и в случае с GlobalStyleSheetManager, мы собираемся создать Singleton для нашего класса DecalSheetManager.

DecalSheetManager (находится в пакете «camo.core.managers») является менеджером для системы декалей. Он обрабатывает XML, который определяет список изображений DecalSheet и координаты для вырезания каждого Decal. Он также хранит коллекцию DecalSheets, чтобы упростить управление созданием сложных таблиц поиска Decal. Вы можете настроить DecalSheets и Decals на DecalSheetManager во время выполнения или с XML. Как только эти данные установлены, DecalSheetManager выходит и получает все изображения, необходимые для изображений DecalSheet.

Теперь мы готовы настроить наш класс GlobalDecalSheetManager. Вам нужно будет создать новый класс с именем «GlobalDecalSheetManager» и поместить его в пакет «com.jessefreeman.managers».

4_create_global_decal_sheet

Вот код для класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.jessefreeman.managers
{
    import camo.core.managers.DecalSheetManager;
 
    public class GlobalDecalSheetManager
    {
 
        public static const INIT:String = «init»;
 
        private static var __instance:DecalSheetManager;
 
        /**
         *
         * @param enforcer
         *
         */
        public function GlobalDecalSheetManager(enforcer:SingletonEnforcer)
        {
            if (enforcer == null)
            {
                throw new Error(«Error: Instantiation failed: Use GlobalDecalSheetManager.instance instead.»);
            }
        }
 
        /**
         *
         * @return
         *
         */
        public static function get instance():DecalSheetManager
        {
            if (GlobalDecalSheetManager.__instance == null)
            {
                GlobalDecalSheetManager.__instance = new DecalSheetManager();
            }
            return GlobalDecalSheetManager.__instance;
        }
 
    }
}
 
internal class SingletonEnforcer{}

К настоящему моменту это должно показаться вам знакомым, так что не на что идти. Давайте поговорим о том, как загрузить XML в DecalSheet и проанализировать его.

Мы собираемся изменить XML-файл DecalSheet в нашей папке htm-template. Чтобы создать наши наклейки, нам нужно знать x, y, ширину и высоту каждого изображения, которое мы хотим использовать. Вот быстрый макет нашего PSD с координатами.

5_decals_coords

Теперь, когда у нас есть все необходимые значения, замените содержимое нашего decahsheet.xml в папке html-template / xml следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?xml version=»1.0″ encoding=»UTF-8″?>
<decalsheet>
    <sheets baseURL=»images/skins»>
        <sheet name=»default» src=»/default.png» preload=»true» w=»570″ h=»359″/>
    </sheets>
    <decals>
        <decal name=»head» sheet=»default» x=»433″ y=»181″ w=»136″ h=»138″/>
        <decal name=»body» sheet=»default» x=»255″ y=»139″ w=»182″ h=»139″/>
        <decal name=»leftArm» sheet=»default» x=»208″ y=»278″ w=»194″ h=»76″/>
        <decal name=»leftFoot» sheet=»default» x=»4″ y=»172″ w=»125″ h=»78″/>
        <decal name=»leftLeg» sheet=»default» x=»128″ y=»172″ w=»122″ h=»78″/>
        <decal name=»rightArm» sheet=»default» x=»251″ y=»17″ w=»182″ h=»122″/>
        <decal name=»rightLeg» sheet=»default» x=»3″ y=»6″ w=»216″ h=»168″/>
    </decals>
</decalsheet>

Этот xml должен быть легок для понимания, мы определяем наш источник DecalSheet, а затем определяем каждый перевод и лист, к которому они принадлежат Обратите внимание, что у листа есть атрибут для предварительной загрузки, мы будем использовать загрузчик DecalSheetManager для предварительной загрузки всех изображений нашего сайта. Это будет играть более важную роль, когда мы предварительно загрузим несколько DecalSheets позже.

DecalSheetManager использует xml для создания DecalSheets и Decals. Сначала нам нужно будет загрузить некоторый XML, а затем передать его в DecalSheetManager в GlobalDecalSheetManager (попробуйте сказать это 3 раза быстрее).

Давайте начнем с добавления следующих методов после нашего метода onPropertySheetLoad в классе Doc:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private function loadDecalSheetData():void
{
    var urlLoader:URLLoader = new URLLoader();
    urlLoader.addEventListener(Event.COMPLETE, onDecalSheetDataLoad, false, 0, true);
    urlLoader.load(new URLRequest(«xml/decalsheet.xml»));
}
 
private function onDecalSheetDataLoad(event:Event):void
{
    // Remove Event Listener
    URLLoader(event.target).removeEventListener(Event.COMPLETE, onDecalSheetDataLoad);
 
    //
    var xml:XML = XML(event.target.data);
    var decalSheetManager:DecalSheetManager = GlobalDecalSheetManager.instance;
    decalSheetManager.addEventListener(LoaderManagerEvent.PRELOAD_NEXT, onPreloadNext, false, 0, true);
    decalSheetManager.addEventListener(LoaderManagerEvent.PRELOAD_DONE, onDecalSheetsLoad, false, 0, true);
    decalSheetManager.parseXML(xml);
}
 
protected function onPreloadNext(event:LoaderManagerEvent):void
{
    trace(«Loading DecalSheet » + event.data.totalPreloaded + » of » + event.data.totalPreloading);
}
 
private function onDecalSheetsLoad(event:LoaderManagerEvent):void
{
    var target:DecalSheetManager = event.target as DecalSheetManager;
    target.removeEventListener(LoaderManagerEvent.PRELOAD_DONE, onDecalSheetsLoad);
    init();
}

Вам также нужно будет импортировать следующее:

1
2
3
import camo.core.managers.DecalSheetManager;
import com.jessefreeman.managers.GlobalDecalSheetManager;
import camo.core.events.LoaderManagerEvent;

Мы только что добавили много кода, поэтому давайте на секунду рассмотрим, что происходит. Сначала мы определяем метод «loadDecalSheetData». Все, что мы делаем здесь — это создаем новый urlLoader и загружаем наш decalsheet.xml. Когда загрузка завершена, мы вызываем «onDecalSheetDataLoad». Этот метод обрабатывает удаление прослушивателя событий из нашего загрузчика URL-адресов и передает XML-файл экземпляру DecalSheetManager, полученному из нашего GlobalDecalSheetManager Singleton. Мы также добавили двух слушателей; один для уведомления о «следующем» инициировании предварительной загрузки, а второй — когда предварительная загрузка завершена. Когда мы закончим загрузку, мы вызываем «onDecalSheetLoad», удаляем наших слушателей и вызываем init.

Теперь нам нужно удалить вызов init из нашего метода onPropertySheetLoad. Замените эту функцию следующим:

1
2
3
4
5
6
7
8
9
private function onPropertySheetLoad(event:Event):void
{
    var target:URLLoader = event.target as URLLoader;
    target.removeEventListener(Event.COMPLETE, onPropertySheetLoad);
 
    propSheet.parseCSS(«global.properties», target.data);
 
    loadDecalSheetData();
}

Если вы компилируете, все должно выглядеть одинаково, но теперь мы загружаем в наш XML-файл DecalSheet вместе с изображением DecalSheet.

6_decal_xml_and_sheet_image

Нам понадобится компонент для отображения нашей декали. Как правило, вы можете воспользоваться свойством фонового изображения BoxModel для автоматической загрузки любого изображения, которое вам понадобится, но поскольку наши части тела должны быть отцентрированы, мы должны расположить их рука.

Давайте начнем с переименования нашего «SimpleDisplay» в «com.jessefreeman.components» на «DecalDisplay».

7_rename

Как только вы это сделаете, откройте класс и замените его код следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.jessefreeman.components
{
    import camo.core.decal.Decal;
    import com.jessefreeman.managers.GlobalDecalSheetManager;
    import com.jessefreeman.components.AbstractComponent;
 
    public class DecalDisplay extends AbstractComponent
    {
        protected var decalInstance:Decal;
 
        public var pixelSnapping:String = «auto»;
 
        public var smoothing:Boolean = true;
 
        public function DecalDisplay(id:String)
        {
            super(this, id);
        }
 
        public function set src(decalName:String):void
        {
            decalInstance = GlobalDecalSheetManager.instance.getDecal(decalName, pixelSnapping, smoothing);
            if (!contains(decalInstance))
                addChild(decalInstance);
        }
    }
}

Как видите, у нас есть несколько свойств, которые мы можем использовать для стилизации этого класса из таблицы свойств. Давайте посмотрим на общедоступные переменные, pixelSnapping и сглаживание должны выглядеть знакомо, если вы уже работали с Bitmap Class. Это просто помогает сделать наши переводные картинки гладкими, когда они покачиваются.

Основной функциональностью класса является установщик для src. Как вы можете видеть, он принимает имя декали, а затем запрашивает наклейку у GlobalDecalSHeetManager. Если наклейка существует, мы добавляем ее на дисплей. Давайте немного поговорим о декалях.

Decal — это растровое изображение, содержащее ссылку на DecalSheet, из которого оно было вырезано. Теперь, когда вы увидели, как мы получаем данные XML в DecalSheetManager, давайте поговорим о том, как получать экземпляры Decal. Когда вы вызываете «getDecal» в DecalSheetManager или DecalSheet, вам необходимо указать имя декаля. Вы можете проверить, существует ли декаль, просмотрев массив «decalName» DecalSheet. Когда запрашивается декаль, ее имя передается родительскому DecalSheet с помощью метода «sample», а BitmapData декаля возвращается в новом экземпляре Decal.

Поскольку все декали содержат ссылку на DecalSheet, из которого она была вырезана, это соединение позволяет декалю получать обновления от своего родительского DecalSheet. Вы можете изменить BitmapData в DecalSheet в любое время так же, как и любой другой экземпляр Bitmap. Этикетки прослушивают события «Event.CHANGE» из родительского листа и, как только событие получено, пересматривают DecalSheet и обновляют свои собственные BitmapData. Позже мы перенастроим целое приложение на лету, изменив BitmapData нашего DecalSheet.

Теперь, когда у нас есть наш DecalDisplay, нам нужно добавить его в наш BobbleContainer. В BobbleContainer добавьте следующий метод после «get active»:

1
2
3
4
5
6
public function set src(value:String):void
{
    decalDisplay = new DecalDisplay(id + «DecalDisplay»);
    decalDisplay.src = value;
    addChildAt(decalDisplay, 0);
}

Также нам нужно создать следующее свойство:

1
protected var decalDisplay:DecalDisplay;

Поэтому все, что мы делаем, это добавляем установщик для src, который мы можем передать в новый экземпляр DecalDisplay. Заметьте, что мы используем «addChildAt»? Поскольку мы добавляем наш ярлык, мы хотим убедиться, что DecalDisplay находится в самом низу списка отображения. Теперь у нас есть наш DecalDisplay, нам просто нужно настроить несколько стилей свойств.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
#body
{
    x: 355;
    y: 229;
    width: 181;
    height: 144;
    src: body;
}
 
#bodyDecalDisplay
{
    x: -84;
    y: -65;
}

Как вы, возможно, заметили ранее, когда мы создаем наши DecalDisplays в BobbleContainer, мы передаем идентификатор BobbleContainer и строку «DecalDisplay», чтобы у каждого экземпляра был уникальный идентификатор. В приведенном выше примере мы добавили src для ссылки на название декали, которую мы хотим использовать, и затем имеем соответствующий стиль со смещением x, y для декали. Замените содержимое вашего «main.properties.css» следующим:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* CSS file */
 
.BobblePerson
{
    part-ids: head body leftArm rightArm leftLeg leftFoot rightLeg;
}
 
.Label
{
    font: Arial Black;
    size: 20px;
    embedFonts: true;
    color: #ffffff;
    anti-alias-type: advanced;
}
 
#siteLabel
{
    text: ANATOMY OF JESSE FREEMAN;
    x: 155;
    y: 60;
    size: 18px;
    rotation: 24px;
    letter-spacing: -2;
    text-height: 30px;
    alpha: .5;
}
 
.BobbleContainer
{
    active: true;
    rollOverForce: 1;
    roll-over-force: 1;
    nodding-force: 0;
    nodding-angle: 0;
    nodding-range: 10;
    nodding-hit: .7;
    nodding-damp: .985;
}
 
/* BobbleContainers */
 
#body
{
    x: 355;
    y: 229;
    src: body;
}
 
#head
{
    x: 449;
    y: 250;
    src: head;
}
 
#leftArm
{
    x: 381;
    y: 313;
    src: leftArm;
}
 
#leftFoot
{
    x: 145;
    y: 213;
    src: leftFoot;
}
 
#leftLeg
{
    x: 263;
    y: 235;
    src: leftLeg;
}
 
#rightArm
{
    x: 419;
    y: 176;
    src: rightArm;
}
 
#rightLeg
{
    x: 275;
    y: 176;
    src: rightLeg;
}
 
 
/* BobbleContainer Labels */
 
#bodyLabel
{
    alpha: 1;
    rotation: 20;
    x: -35;
    y: -30;
    text-align: center;
    auto-size: center;
     
}
 
#leftArmLabel
{
    text: bFreeDesign;
    x: -90;
    y: 25;
    rotation: -9;
    size: 18;
    letter-spacing: -3;
}
 
#leftFootLabel
{
    text: eMail;
    x: -78;
    y: -13;
    rotation: 6;
}
 
#leftLegLabel
{
    text: FlashBum;
    x: -95;
    y: -40;
    rotation: 9;
}
 
#rightArmLabel
{
    text: FlashArtOfWar;
    x: -80;
    y: -75;
    rotation: 32;
    font-size: 16;
    letter-spacing: -1;
}
 
#rightLegLabel
{
    text: iLikeToDream;
    x: -157;
    y: -83;
    rotation: 27;
}
 
/* BobbleContainer Displays */
 
#bodyDecalDisplay
{
    x: -84;
    y: -65;
}
 
#headDecalDisplay
{
    x: -20;
    y: -18;
}
 
#leftArmDecalDisplay
{
    x: -162;
    y: -11;
}
 
#leftFootDecalDisplay
{
    x: -104;
    y: -20;
}
 
#leftLegDecalDisplay
{
    x: -103;
    y: -43;
}
 
#rightArmDecalDisplay
{
    x: -136;
    y: -104;
}
 
#rightLegDecalDisplay
{
    x: -192;
    y: -142;
}

Теперь у вас есть чистый PropertySheet с правильно подключенными нашими наклейками. Если вы делаете компиляцию, вы должны увидеть все части тела на своих местах вместе с нашими ярлыками.

8_bobble_head_preview

Когда мы начнем добавлять интерактивность в наше приложение, нам понадобится настраиваемое событие для отслеживания взаимодействия мыши с частями тела. Давайте создадим новый класс с именем «FocusEvent» в «com.jessefreeman.events»

9_create_focus_event

Вот код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package com.jessefreeman.events
{
    import flash.events.Event;
 
    public class FocusEvent extends Event
    {
        public static const IN_FOCUS:String = «inFocus»;
        public static const LOST_FOCUS:String = «lostFocus»;
         
        public var text : *;
        public var skinName : String;
 
        public function FocusEvent(type:String, text:String = «» , skinName:String = «default», bubbles:Boolean=false, cancelable:Boolean=false)
        {
            this.text = text;
            this.skinName = skinName;
            super(type, bubbles, cancelable);
        }
         
    }
}

Итак, в этом классе FocusEvent мы добавили два новых свойства в конструктор события по умолчанию: «text» и «skinName». Текст будет меткой части тела, которую мы перевернем, а skinName будет использоваться позже, когда мы начнем динамически перерисовывать наше приложение. У нас также есть две константы, представляющие наши состояния, «inFocus» и «lostFocus».

Давайте отправим это событие, перейдя в класс BobbleContainer и добавив следующую строку в конец метода onRollOver:

1
dispatchEvent( new FocusEvent( FocusEvent.IN_FOCUS, rollOverText, «default», true, true ) );

Затем добавьте следующее в метод «onRollOut»:

1
dispatchEvent( new FocusEvent( FocusEvent.LOST_FOCUS, rollOverText, «default», true, true ) );

Также убедитесь, что вы импортируете FocusEvent:

1
import com.jessefreeman.events.FocusEvent;

Теперь у нас есть два события, которые сообщают нам о состоянии BobbleContainer. Прежде чем мы закончим, нам нужно добавить новую открытую переменную в BobbleContainer:

1
public var rollOverText : String = «»;

Мы передаем эту переменную в событие in focus, которое отправляется. Вам нужно будет изменить ваш CSS с новым RollOverText. Замените эти стили в блоке комментариев / * BobbleContainers * / следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/* BobbleContainers */
 
#body
{
    x: 355;
    y: 229;
    rollOverLabel:;
    src: body;
}
 
#head
{
    x: 449;
    y: 250;
    src: head;
    rollOverText: RESUME;
}
 
#leftArm
{
    x: 381;
    y: 313;
    src: leftArm;
    rollOverText: HIRE;
}
 
#leftFoot
{
    x: 145;
    y: 213;
    src: leftFoot;
    rollOverText: CONTACT;
}
 
#leftLeg
{
    x: 263;
    y: 235;
    src: leftLeg;
    rollOverText: PORTFOLIO;
}
 
#rightArm
{
    x: 419;
    y: 176;
    src: rightArm;
    rollOverText: BLOG;
}
 
#rightLeg
{
    x: 275;
    y: 176;
    src: rightLeg;
    rollOverText: MY ART;
}

Теперь у нас есть все всплывающие тексты, пора их отображать. Возможно, вы заметили, что часть «body» не имеет rollOverText. Мы собираемся отобразить текст части тела здесь. Давайте перейдем к BobblePerson и сделаем несколько модификаций.

В конце метода «createParts» добавьте следующие два прослушивателя событий:

1
2
display.addEventListener( FocusEvent.IN_FOCUS, onContainerRollOver );
display.addEventListener( FocusEvent.LOST_FOCUS, onContainerRollOut );

Ниже метода «createParts» добавьте следующее:

01
02
03
04
05
06
07
08
09
10
11
12
public function onContainerRollOver(event:FocusEvent):void
{
    if (event.target != partDisplay)
    {
        partDisplay.label.text = event.text;
    }
}
 
public function onContainerRollOut(event:FocusEvent):void
{
    partDisplay.label.text = «»;
}

Нам нужно добавить новый метод получения, поэтому поместите следующее в get «partIds».

1
2
3
4
5
6
public function get partDisplay():BobbleContainer
{
    var index:int = _partIds.indexOf(partDisplayId);
 
    return (index != -1) ?
}

Мы почти у цели, теперь давайте удостоверимся, что у вас есть следующее свойство:

1
public var partDisplayId : String;

Затем импортируйте следующий класс:

1
import com.jessefreeman.events.FocusEvent;

Прежде чем мы протестируем это, нам просто нужно обновить наш стиль css «.BobblePerson», чтобы включить следующее свойство:

1
part-display-id: body;

Теперь сделайте компиляцию и переверните части тела.

10_roll_over_test

Обратите внимание, как мы можем изменить часть тела, которая будет отображать текст в любое время, изменив id-display-части в нашем CSS. Давайте добавим окончательный набор логики на наш сайт.

Теперь мы собираемся добавить несколько слушателей, чтобы отслеживать щелчок BodyPart, чтобы мы могли открыть соответствующий URL в новом окне. Перейдите в BobbleContainer и замените «addEventListeners» и «removeEventListeenrs» следующим кодом:

01
02
03
04
05
06
07
08
09
10
11
12
13
protected function addEventListeners(target : IEventDispatcher) : void
{
    target.addEventListener( MouseEvent.ROLL_OVER, onRollOver );
    target.addEventListener( MouseEvent.ROLL_OUT, onRollOut );
    target.addEventListener( MouseEvent.CLICK, onClick );
}
 
protected function removeEventListeners(target : IEventDispatcher) : void
{
    target.removeEventListener( MouseEvent.ROLL_OVER, onRollOver );
    target.removeEventListener( MouseEvent.ROLL_OUT, onRollOut );
    target.removeEventListener( MouseEvent.CLICK, onClick );
}

Мы просто добавляем прослушиватель для Click мыши. Добавьте следующий метод ниже «onRollOut»:

1
2
3
4
5
protected function onClick(event : MouseEvent) : void
{
    if(url)
        navigateToURL( url, «_self» );
}

Давайте добавим новую публичную переменную для наших URL:

1
public var url : URLRequest;

Импортируйте следующие классы:

1
2
import flash.net.URLRequest;
import flash.net.navigateToURL;

Все, что нам нужно сделать, — это изменить наш PropertySheet, чтобы он включал URL для каждой части, заменив блок комментария «/ * BobbleContainers * /» следующим текстом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/* BobbleContainers */
 
#body
{
    x: 355;
    y: 229;
    rollOverLabel:;
    src: body;
}
 
#head
{
    x: 449;
    y: 250;
    src: head;
    rollOverText: RESUME;
    url: url(«http://www.linkedin.com/in/jessefreeman»);
}
 
#leftArm
{
    x: 381;
    y: 313;
    src: leftArm;
    rollOverText: HIRE;
    url: url(«http://www.bfreedesign.com»);
}
 
#leftFoot
{
    x: 145;
    y: 213;
    src: leftFoot;
    rollOverText: CONTACT;
    url: url(«mailto:[email protected]»);
}
 
#leftLeg
{
    x: 263;
    y: 235;
    src: leftLeg;
    rollOverText: PORTFOLIO;
    url: url(«http://www.flashbum.com»);
}
 
#rightArm
{
    x: 419;
    y: 176;
    src: rightArm;
    rollOverText: BLOG;
    url: url(«http://www.flashartofwar.com»);
}
 
#rightLeg
{
    x: 275;
    y: 176;
    src: rightLeg;
    rollOverText: MY ART;
    url: url(«http://www.iliketodream.com»);
}

Обратите внимание, как мы добавили свойства URL. Вот как мы говорим CSS-анализатору Camo преобразовывать URL-адреса в URL-запросы. Теперь, когда пользователь нажимает на часть тела, мы просто передаем URL-запрос, заданный PropertyStyleSheet, в класс «navigateToURL».

Если вы хотите, чтобы детали Bobble выступали в качестве кнопок, просто добавьте следующее к стилю «.BobbleContainer»:

1
2
3
button-mode: true;
use-hand-cursor: true;
mouse-children: false;

Теперь все классы BobbleContainer будут автоматически действовать как кнопки. Возможно, вы захотите изменить еще один стиль, «#body», чтобы у него не было интерактивности с мышью. Просто добавьте следующее в селектор свойств:

1
2
3
button-mode: false;
use-hand-cursor: false;
mouse-children: false;

Теперь он отменяет настройки класса по умолчанию и не будет взаимодействовать с мышью.

Давайте посмотрим, как сделать продвинутый скиннинг.

Когда вы открывали PSD, вы, возможно, заметили несколько дополнительных «скинов» в папке Body Skin.

Я подготовил для нас следующие скины. Вы можете скачать zip здесь и поместить скины в папку html-template / images / skins.

Теперь у вас есть каждый скин, давайте посмотрим, как мы можем загрузить их все.

Загрузка нескольких изображений DecalSheet так же проста, как изменение xml. Давайте заменим наш decalsheet.xml следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?xml version=»1.0″ encoding=»UTF-8″?>
<decalsheet>
    <sheets baseURL=»images/skins»>
        <sheet name=»default» src=»/default.png» preload=»true» w=»570″ h=»359″/>
        <sheet name=»iliketodream» src=»/iliketodream_skin.png» preload=»true» w=»570″ h=»359″/>
        <sheet name=»flashbum» src=»/flashbum_skin.png» preload=»true» w=»570″ h=»359″/>
        <sheet name=»bfreedesign» src=»/bfreedesign.png» preload=»true» w=»570″ h=»359″/>
        <sheet name=»artofwar» src=»/artofwar_skin.png» preload=»true» w=»570″ h=»359″/>
    </sheets>
    <decals>
        <decal name=»head» sheet=»default» x=»433″ y=»181″ w=»136″ h=»138″/>
        <decal name=»body» sheet=»default» x=»255″ y=»139″ w=»182″ h=»139″/>
        <decal name=»leftArm» sheet=»default» x=»208″ y=»278″ w=»194″ h=»76″/>
        <decal name=»leftFoot» sheet=»default» x=»4″ y=»172″ w=»125″ h=»78″/>
        <decal name=»leftLeg» sheet=»default» x=»128″ y=»172″ w=»122″ h=»78″/>
        <decal name=»rightArm» sheet=»default» x=»251″ y=»17″ w=»182″ h=»122″/>
        <decal name=»rightLeg» sheet=»default» x=»3″ y=»6″ w=»216″ h=»168″/>
    </decals>
</decalsheet>

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

12_skins_being_loaded

Теперь, когда мы загружаем свои скины, давайте добавим логику для динамического изменения растровых данных скина. Давайте перейдем к нашему классу BobblePerson и добавим следующие две функции:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
protected function saveDefaultBitmapData():void
{
    defaultSkin = GlobalDecalSheetManager.instance.getSheet(«default»);
    defaultSkinBMD = defaultSkin.bitmapData.clone();
}
 
protected function switchSkin(skinName:String = «default»):void
{
    var newSkinBitmapData:BitmapData;
 
    if (skinName == «default»)
    {
        newSkinBitmapData = defaultSkinBMD.clone();
    }
    else
    {
        newSkinBitmapData = GlobalDecalSheetManager.instance.getSheet(skinName).bitmapData.clone();
    }
 
    if (newSkinBitmapData)
        defaultSkin.bitmapData = newSkinBitmapData;
}

Давайте поговорим о том, что здесь происходит. Мы собираемся воспользоваться изящной функцией системы DecalSheet от Camo, заменив растровые данные нашей обложки по умолчанию на BitmapData из других оболочек. Для этого нам нужно иметь ссылку на стандартный DecalSheet, а также его BitmapData. Мы делаем это в «saveDefaultBitmapData». Далее нам нужно добавить логику для переключения скинов. Это происходит в методе «switchSkin». Как видите, мы создали переменную для хранения наших новых BitmapData.

Далее мы проверяем, является ли скин «default» или что-то еще. Если это скин по умолчанию, мы получаем BitmapData из «defaultSkinBMD». Если это другой скин, мы попросим экземпляр GlobalDecalSheetManager для этого листа. Наконец, мы удостоверимся, что в нашей переменной newSkinBitmapData есть действительные BitmapData, а затем установили для BitmapData нашей темы оформления по умолчанию значение newSkinBitmapData.

Нам нужно добавить следующие переменные:

1
2
protected var defaultSkin:DecalSheet;
protected var defaultSkinBMD:BitmapData;

и убедитесь, что вы импортировали класс BitmapData:

1
2
3
import flash.display.BitmapData;
import camo.core.decal.DecalSheet;
import com.jessefreeman.managers.GlobalDecalSheetManager;

Наконец, мы вызовем «saveDefaultBitmapData» в установщике для «partIds». Убедитесь, что ваш сеттер выглядит так:

1
2
3
4
5
6
public function set partIds(value:Array):void
{
    _partIds = value;
    saveDefaultBitmapData();
    createParts();
}

Теперь давайте перейдем к нашему классу BobbleContainer и добавим следующее свойство:

1
public var skin:String = «default»;

Далее вам нужно изменить dispatchEvent в методе «onRollOver», чтобы он выглядел так:

1
dispatchEvent(new FocusEvent(FocusEvent.IN_FOCUS, rollOverText, skin, true, true));

Заметьте, как мы пропускаем значение скина через событие? Это скажет телу правильную кожу, чтобы использовать, когда есть переворачивание.

Давайте вернемся к нашему BobblePerson и изменим методы «onContainerRollOver» и «onContainerRollOut», чтобы они выглядели так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public function onContainerRollOver(event:FocusEvent):void
{
    if (event.target != partDisplay)
    {
        partDisplay.label.text = event.text;
        switchSkin(event.skinName);
    }
}
 
public function onContainerRollOut(event:FocusEvent):void
{
    partDisplay.label.text = «»;
    switchSkin(«default»);
}

Теперь нам просто нужно изменить наш PropertySheet, чтобы добавить имя скина к частям тела. Замените блок комментария / * BobbleContainers * / следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/* BobbleContainers */
 
#body
{
    x: 355;
    y: 229;
    rollOverLabel:;
    src: body;
    button-mode: false;
    use-hand-cursor: false;
    mouse-children: false;
}
 
#head
{
    x: 449;
    y: 250;
    src: head;
    rollOverText: RESUME;
    url: url(«http://www.linkedin.com/in/jessefreeman»);
    skin: default;
}
 
#leftArm
{
    x: 381;
    y: 313;
    src: leftArm;
    rollOverText: HIRE;
    url: url(«http://www.bfreedesign.com»);
    skin: bfreedesign;
}
 
#leftFoot
{
    x: 145;
    y: 213;
    src: leftFoot;
    rollOverText: CONTACT;
    url: url(«mailto:[email protected]»);
    skin: default;
}
 
#leftLeg
{
    x: 263;
    y: 235;
    src: leftLeg;
    rollOverText: PORTFOLIO;
    url: url(«http://www.flashbum.com»);
    skin: flashbum;
}
 
#rightArm
{
    x: 419;
    y: 176;
    src: rightArm;
    rollOverText: BLOG;
    url: url(«http://www.flashartofwar.com»);
    skin: artofwar;
}
 
#rightLeg
{
    x: 275;
    y: 176;
    src: rightLeg;
    rollOverText: MY ART;
    url: url(«http://www.iliketodream.com»);
    skin: iliketodream;
}

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

13_reskin_preview

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

Теперь наш сайт готов, и мы готовы развернуть его на сервере. Это довольно легко сделать в Flex Builder и сделать шаг навстречу большинству людей. Просто зайдите в меню Project и выберите Export Release Build.

14_bin_release

После этого у вас будет новая папка bin-release вместе с bin-debug. Все выглядит одинаково, но если вы посмотрите на наш BobbleHeadApp.swf, вы заметите, что сборка релиза составляет около 24 Кб, а версия отладки — 36 Кб. Это всего 66% от первоначального размера. Я знаю, когда вы говорите только о нескольких k, это не главное, но каждый k считается. Кроме того, в более крупных проектах это может быть значительной экономией.

Теперь вы готовы скопировать эту папку bin-release на ваш FTP-сервер и запустить ее.

Как видите, мы создали простой Flash-сайт с использованием Flash Camouflage менее чем за 30 шагов. К настоящему времени вы должны лучше понимать возможности включения декалей и CSS в ваш следующий проект. Вы также видели, как легко создавать компоненты, которые работают с тремя основными функциями Flash Camo. Как и во всех рамках, существует кривая обучения, и это лишь малая часть того, что возможно. Кроме того, Flash Camo все еще находится в бета-версии, поэтому могут быть небольшие ошибки или очистка кода по мере развития проекта.

Если у вас возникнут какие-либо проблемы, пожалуйста, оставьте комментарий или отправьте проблему в список проблем . Помните, что Flash Camo является полностью открытым исходным кодом, вы должны проверить код и посмотреть, что происходит под капотом. Используется много продвинутых технологий, поэтому это отличное место, чтобы узнать, как составлять фреймворк. Если вы используете Camo в одном из ваших проектов, дайте мне знать ..

Спасибо за подписку!