Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > alatar

Оценить эту запись

Скин для IconButton в стиле Windows 7

Запись от alatar размещена 02.02.2011 в 13:55
Обновил(-а) alatar 19.11.2013 в 00:06

Этот пост продолжение предыдущего.

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

И так начнем.

Анатомия скина.

Скин будет состоять из двух полупрозрачны обводок (белая и черная)
Код:
<s:Rect id="blackBorder"
        top="0"
        bottom="0"
        left="0"
        right="0"
        radiusX="4">
    <s:stroke>
        <s:SolidColorStroke color="0" alpha=".3"/>
    </s:stroke>
</s:Rect>

<s:Rect id="whiteBorder"
        top="1"
        bottom="1"
        left="1"
        right="1"
        radiusX="2">
    <s:stroke>
        <s:SolidColorStroke color="0xFFFFFF" alpha=".3"/>
    </s:stroke>
</s:Rect>
Полупрозрачной градиентной заливки, которая в состоянии "over" и "down" будет менять прозрачность.
Код:
<s:Rect id="fill"
        top="1"
        bottom="1"
        left="1"
        right="1"
        radiusX="2">
    <s:fill>
        <s:LinearGradient rotation="90">
            <s:GradientEntry color="0xFFFFFF" alpha="0.3" alpha.down=".8" ratio="0"/>
            <s:GradientEntry color="0xFFFFFF" alpha="0.05" alpha.down=".3" ratio="0.6"/>
            <s:GradientEntry color="0xFFFFFF" alpha="0.01" alpha.down=".8" ratio="1"/>
        </s:LinearGradient>
    </s:fill>
</s:Rect>
Рефлекса, для имитации отражений на стекле (ну или пластике).
Код:
<s:Path id="highlight"
        top="1"
        bottom="1"
        left="1"
        right="1"
        data="L 20 0 L 20 5 Q 10 2 0 15 L 0 0">
    <s:fill>
        <s:RadialGradient id="highlightGradient" x="30" y="0">
            <s:GradientEntry color="0xFFFFFF" alpha="0.5"/>
            <s:GradientEntry color="0xFFFFFF" alpha="0"/>
        </s:RadialGradient>
    </s:fill>
</s:Path>
Ну и самое интересное — градиент, который смещается в зависимости от положения курсора над кнопкой. Он будет появляться при наведении курсора и прятаться, когда курсор уйдет с кнопки.
Код:
<s:Rect id="mouseHighlight"
        top="1"
        bottom="1"
        left="1"
        right="1"
        radiusX="2">
    <s:fill>
        <s:RadialGradient id="mouseHighlightGradient">
            <s:GradientEntry color="{_averageColor}" alpha="1"/>
            <s:GradientEntry color="{_averageColor}" alpha="0"/>
        </s:RadialGradient>
    </s:fill>
</s:Rect>
Ну и остальная скучная дребедеть, типа места под иконку и лейбла.

Тут есть один момент. Градиенты надо отмасштабировать, но так как масштаб задается в пикселях, придется при изменении размеров вносить коррективы.

Код AS3:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    if (mouseHighlightGradient)
    {
        mouseHighlightGradient.y = unscaledHeight;
        mouseHighlightGradient.scaleX = unscaledWidth * 3;
        mouseHighlightGradient.scaleY = unscaledHeight * 2;
    }
 
    highlightGradient.scaleX = unscaledWidth * 2 - unscaledWidth * .2;
    highlightGradient.scaleY = unscaledHeight;
 
    super.updateDisplayList(unscaledWidth, unscaledHeight);
}
Оживление картинки

Непосредственно скин, не реагирует на события мыши, поэтому подписываться будем у hostComponent. Ну и так как mouseHighlight появляется только тогда, когда курсор находится над кнопкой, делать это будем при смене состояния.
Код AS3:
override protected function stateChanged(oldState:String, newState:String, recursive:Boolean):void
{
    super.stateChanged(oldState, newState, recursive);
 
    if (newState == "over" || newState == "down")
    {
        hostComponent.addEventListener(MouseEvent.MOUSE_MOVE, hostComponent_mouseMoveHandler);
    }
    else
    {
        hostComponent.removeEventListener(MouseEvent.MOUSE_MOVE, hostComponent_mouseMoveHandler);
    }
}
 
private function hostComponent_mouseMoveHandler(event:MouseEvent):void
{
    mouseHighlightGradient.x = hostComponent.mouseX;
}
Теперь градиент живенько бегает за курсором. Но не хватает еще одной фичи. В Win 7 цвет градиента зависит от среднего цвета иконки. Пришло время добавить эту функциональность.

Для начала определим момент, когда иконка будет добавлена в скин, что бы получить к ней доступ.
Код AS3:
override protected function createChildren():void
{
    super.createChildren();
 
    iconGroup.addEventListener(ElementExistenceEvent.ELEMENT_ADD, iconGroup_ElementExistenceHandler);
    iconGroup.addEventListener(ElementExistenceEvent.ELEMENT_REMOVE, iconGroup_ElementExistenceHandler);
}
Теперь надо отследить момент, когда иконка поменялась. Тут нас ждет засада. Ввиду того, что в роли иконки у IconButton может выступать практически все, что угодно — событие COMPLETE для этого не годится, так как возникает только в случаях когда иконка загружалась извне.

Слава Цифре есть событие UPDATE_COMPLETE, которое в данном случае идеально подходит.
Код AS3:
private function iconGroup_ElementExistenceHandler(event:ElementExistenceEvent):void
{
    switch (event.type)
    {
        case ElementExistenceEvent.ELEMENT_ADD:
            event.element.addEventListener(FlexEvent.UPDATE_COMPLETE, icon_updateComplete);
            break
        case ElementExistenceEvent.ELEMENT_REMOVE:
            event.element.removeEventListener(FlexEvent.UPDATE_COMPLETE, icon_updateComplete);
            break
    }
}
Теперь осталось посчитать средний цвет и присвоить его градиенту.

Код AS3:
private function icon_updateComplete(event:FlexEvent):void
{
    _averageColor = calculateAverageColor(event.currentTarget as DisplayObject);
}
 
[Bindable]
private var _averageColor:uint = 0xFFFFFF;
 
private function calculateAverageColor(source:DisplayObject):uint
{
    var averageColorBmd:BitmapData = new BitmapData(source.width, source.height);
    averageColorBmd.draw(source);
 
    var red:uint = 0;
    var green:uint = 0;
    var blue:uint = 0;
 
    var count:int = 0;
    var pixel:uint;
 
    for (var x:int = 0; x < averageColorBmd.width; x++)
    {
        for (var y:int = 0; y < averageColorBmd.height; y++)
        {
            pixel = averageColorBmd.getPixel(x, y);
 
            red += pixel >> 16 & 0xFF;
            green += pixel >> 8 & 0xFF;
            blue += pixel & 0xFF;
 
            count++
        }
    }
 
    red /= count;
    green /= count;
    blue /= count;
 
    return red << 16 | green << 8 | blue;
}
iconbutton.swf   (270.4 Кб)


P.S. Я внес изменения в IconButton, она теперь наследуется от ButtonBase для совместимости с будущими версиями фреймворка. Если вдруг она кому нибудь понадобится, берите исходники отсюда.
Изображения
Тип файла: jpg button.JPG (11.1 Кб, 496 просмотров)
Вложения
Тип файла: zip iconbutton.zip (283.6 Кб, 171 просмотров)
Тип файла: swf iconbutton.swf (270.4 Кб, 237 просмотров)
Размещено в Flex , Flex 4
Комментарии 2 Отправить другу ссылку на эту запись
Всего комментариев 2

Комментарии

Старый 02.02.2011 14:39 ChuwY вне форума
ChuwY
 
Аватар для ChuwY
Отличная штука. Тоже очень нравятся такие кнопки.
И очень же захотелось украсть =D
Надо будет на досуге переписать на чистый as и сделать компонент.
Старый 04.08.2011 17:06 Apikaster вне форума
Apikaster
Респект ...
Описал классно ...
Тоже на досуге компонент сделаю и в swc откомпиляю ...
Кому надо обращайтесь ...
 

 


Часовой пояс GMT +4, время: 23:53.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2022, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.