Создание кнопки из растрового изображения может быть утомительным. Если вы используете Flash IDE, вы можете создать маску, чтобы определить, какие пиксели являются частью кнопки, а какие нет, но в любом другом рабочем процессе весь прямоугольник, содержащий растровое изображение, включая любые прозрачные пиксели, будет кликабельным. , В этом уроке вы узнаете, как автоматически сделать все прозрачные пиксели не кликабельными всего за несколько строк кода.
Окончательный результат предварительного просмотра
Давайте посмотрим на конечный результат, к которому мы будем стремиться:
Обратите внимание, что курсор в виде руки появляется только при наведении курсора на фактическое изображение; даже щели в волосах не вызывают его появления. И это не только для показа: нажатия кнопок регистрируются только при нажатии на эти области.
Введение: что такого особенного?
На первый взгляд, SWF выше выглядит очень просто. Но посмотрите поближе! Обратите внимание, что в приведенной выше демонстрации нажатие кнопки считается только в том случае, если вы щелкнете где-то на фактическом изображении. Это не то, что обычно происходит. Поскольку растровое изображение всегда является прямоугольником, нажатие в любом месте его прямоугольника обычно считается нажатием кнопки. Взгляните на пример ниже, где я обрисовал границу прямоугольника нашего изображения. Здесь вы можете щелкнуть в любом месте внутри прямоугольника, включая прозрачные области.
Как видите, это не то, что мы хотим! Для начала, пользователь может случайно нажать кнопку, когда он этого не хочет. Кроме того, это выглядит странно, когда курсор в виде руки появляется над пустым пространством. В этом уроке вы узнаете, как легко исправить эти проблемы.
Если вы еще не знакомы с объектно-ориентированным программированием или FlashDevelop , я рекомендую проверить предоставленные ссылки перед началом этого урока.
Шаг 1: Начало работы
Откройте FlashDevelop и создайте новый проект AS3 (« Проект»> «Новый проект» ) и назовите его как BitmapButtonProj
. Справа откройте папку src и дважды щелкните Main.as
чтобы открыть ее. Добавьте новый класс в ваш проект ( щелкните правой кнопкой мыши / src /> Добавить> Новый класс ) с именем BitmapButton
Шаг 2: встраивание изображения
Теперь нам нужно изображение для работы. Вот тот, который я использую:
Чтобы использовать растровое изображение (например, файл .jpeg или файл .png) в ActionScript 3, мы должны встроить его. FlashDevelop делает это легко. После сохранения указанного выше изображения где-нибудь щелкните правой кнопкой мыши папку lib справа, наведите курсор мыши на кнопку « Добавить» и выберите параметр « Актив библиотеки» .
Если вы хотите использовать собственное изображение, обязательно выберите его с прозрачностью.
Изображение, которое вы выбрали, теперь появится в папке lib в FlashDevelop. Щелкните правой кнопкой мыши изображение и выберите « Создать код для вставки» .
1
2
3
4
|
public class Main extends Sprite
{
[Embed(source = «../lib/face.png»)]
private var ButtonImg:Class;
|
Этот код embeds
изображение в наш проект. Всякий раз, когда вы встраиваете изображение, вам нужно определить на следующей строке класс, который представляет внедренное изображение. В этом случае наш класс называется ButtonImg.
Шаг 3: Добавление TextField
Далее мы добавим TextField
чтобы отобразить, сколько раз мы нажали кнопку (которая будет добавлена далее). Добавьте это в Main()
:
1
2
3
4
5
6
|
clicksTextField = new TextField();
clicksTextField.width = stage.stageWidth;
clicksTextField.defaultTextFormat = new TextFormat(null, 14, 0, true, false, false, null, null, TextFormatAlign.CENTER);
clicksTextField.text = «Button Presses: » + numClicks;
clicksTextField.mouseEnabled = false;
addChild(clicksTextField);
|
Приведенный выше код просто форматирует текст для отображения в верхней части нашего проекта. Не пропустите, как мы объявили наш TextField
в строке 15.
Шаг 4: Добавление кнопки
Этот код также должен идти в Main()
:
кнопка var: BitmapButton = new BitmapButton (ButtonImg); button.x = stage.stageWidth / 2 - button.width / 2; button.y = stage.stageHeight / 2 - button.height / 2; AddChild (кнопка); button.addEventListener (MouseEvent.CLICK, onButtonClick);
Когда мы создаем экземпляр BitmapButton
в строке 36, мы передаем наш класс встроенного изображения в качестве параметра. Это будет использоваться классом BitmapButton
. После этого мы можем просто обработать наш экземпляр BitmapButton
как любой другой DisplayObject
: мы можем позиционировать его и добавить прослушиватель MouseEvent.CLICK
как обычно.
Шаг 5: Заставить кнопку что-то сделать
Добавьте эту функцию обработчика событий в Main.as
:
1
2
3
4
5
|
private function onButtonClick(e:MouseEvent):void
{
numClicks++;
clicksTextField.text = «Button Presses: » + numClicks;
}
|
Последний фрагмент кода в нашем Main
классе — это прослушиватель событий для нажатий кнопок. В нем мы просто добавляем один к количеству кликов, numClicks,
и обновляем текст в clicksTextField.
Шаг 6: Конструктор BitmapButton
Переверните на BitmapButton.as
. Сначала импортируйте эти классы:
1
2
3
4
|
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.MouseEvent;
|
Затем объявите это:
1
2
|
private var bitmapData:BitmapData;
private const THRESHOLD:Number = 0;
|
Вы должны убедиться, что класс BitmapButton
расширяет Sprite
, поскольку Bitmap
само по себе не может иметь никакой интерактивности мыши. (Класс Bitmap
не расширяет InteractiveObject .)
01
02
03
04
05
06
07
08
09
10
|
public function BitmapButton(ImageData:Class)
{
var image:Bitmap = new ImageData();
addChild(image);
bitmapData = image.bitmapData;
addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
addEventListener(MouseEvent.CLICK, onClick);
}
|
В нашем конструкторе BitmapButton
мы выполнили несколько важных вещей.
- Сначала мы создаем новое
Bitmap
image
с именемimage
из класса изображения, передаваемого в качестве параметра конструктору. - Затем мы добавляем этот
Bitmap
как дочерний элемент нашегоSprite
. - Затем мы устанавливаем значение
bitmapData
равнымbitmapData
нашего изображения. - Наконец, мы добавляем
MOUSE_MOVE
событийCLICK
иMOUSE_MOVE
.
Шаг 7: прослушиватель событий MOUSE_MOVE
1
2
3
4
5
|
private function onMouseMove(e:MouseEvent):void
{
var pixel:uint = bitmapData.getPixel32(mouseX, mouseY);
useHandCursor = buttonMode = ((pixel >>>24) > THRESHOLD);
}
|
Наш простой выглядящий слушатель событий MOUSE_MOVE
— это настоящий мозг нашего класса. Его основная цель — определить, находится ли курсор мыши над прозрачным пикселем или нет. Давайте посмотрим, как это происходит.
Функция getPixel32 ()
Первая строка получает цвет и прозрачность пикселя, над которым в данный момент находится курсор. Для этого мы используем метод getPixel32()
переменной bitmapData
(который, помните, является представлением растровых данных нашего изображения).
Мы должны передать координаты x и y в getPixel32()
, поэтому, естественно, мы используем положение мыши.
Затем вызов возвращает uint
представляющую цвет и прозрачность пикселя в указанном нами месте.
Цвета во Flash обычно обрабатываются как шестнадцатеричная uint
в формате RRGGBB. Первые две цифры представляют количество красного цвета, следующие две — зеленый, а последние две — синий. Однако getPixel32()
предоставляет нам специальную uint
представляющую наш пиксель в формате AARRGGBB. Здесь первые две цифры представляют альфа или степень прозрачности от 00 (прозрачный) до FF (непрозрачный).
Так, например, FF980000
будет представлять полностью непрозрачный красный цвет, а 00980000
будет представлять полностью прозрачный красный цвет. Обычно вы видите их в виде 0xFF980000
или 0x0098000
: «0x» позволяет вам (и Flash!) Знать, что число в шестнадцатеричном (0-f), а не десятичном (0-9).
Побитовый беззнаковый правый оператор сдвига
На данный момент у нас есть uint
называемый pixel
который содержит цвет и альфа пикселя под нашей мышью в формате AARRGGBB. К сожалению, это слишком много информации. Все, что нас волнует, это прозрачность этого пикселя или части АА.
Вы можете написать математическое выражение, чтобы получить этот раздел — фактически, int(pixel/Math.pow(16,6))
будет работать. Это несколько неловкое утверждение, однако, и медленнее с точки зрения производительности, чем другой вариант, который у нас есть: побитовый беззнаковый оператор правого сдвига, >>>
.
Наша переменная pixel
— это просто двоичное число для Flash. Обычно мы пишем его в шестнадцатеричном формате, чтобы сделать его более читабельным. Не вдаваясь в подробности, каждая цифра шестнадцатеричного числа может быть представлена строкой из четырех двоичных цифр, каждая из которых либо 0, либо 1. (Таким образом, шестнадцатеричное число использует цифры 0-f, десятичное число — 0-9, и двоичный использует 0-1.)
Скажем, у нас есть шестнадцатеричное число, D4. В двоичном виде это будет представлено как 11010100. Обратите внимание, как мы используем восемь двоичных цифр для двоичного представления: в четыре раза больше, чем в шестнадцатеричном.
Имея это в виду, давайте посмотрим, что на самом деле делает оператор >>>
. Давайте используем наш предыдущий пример, шестнадцатеричное число D4 или 0xD4
для ясности. Теперь давайте использовать >>>
как так:
1
|
0xD4 >>> 4
|
Обратите внимание, что 4 — нормальное десятичное представление числа (в начале нет «0x»). Это выражение, по сути, сдвигает каждую двоичную цифру в D4 на четыре позиции вправо и забывает о любой цифре, которая будет выходить за конец числа.
0xD4 в двоичном виде — 11010100. Примените четыре смены, и оно станет 1101. В шестнадцатеричном виде это 0xD.
Если у вас возникли проблемы с пониманием этого, представьте двоичные цифры как блоки, расположенные справа от таблицы. Оператор >>>
аналогичен перемещению блоков вправо. Вот наш оригинальный двоичный номер:
Теперь вот наш новый номер, после того как мы сделаем 0xD4 >>> 4
:
Заметьте, как после того, как мы сместили 0xD4 на 4 бита, мы получили всего 0xD? Это не совпадение. Как сказано выше, каждая шестнадцатеричная цифра состоит из 4 двоичных цифр — поэтому, каждый раз, когда мы сдвигаем ее вправо на 4, мы по существу выбиваем одну шестнадцатеричную цифру с конца. Вы, вероятно, можете увидеть, куда мы идем с этим!
Вернемся к нашему пикселю в формате 0xAARRGGBB. Если мы сместим его на 24, мы фактически сместимся на 6 шестнадцатеричных цифр. Это означает, что часть RRGGBB удаляется, и в итоге у нас остается только часть 0xAA, которая является нашим альфа-компонентом.
Быстрый числовой пример: скажем, наш пиксель равен FF980000. В двоичном виде это 1111 1111 1001 1000 0000 0000 0000 0000. (Каждая группа из 4 цифр представляет одну шестнадцатеричную цифру.) Когда мы сдвигаем это значение на 24, мы просто получаем 1111 1111, или FF, наши две цифры прозрачности.
Посмотрите на это снова:
1
|
useHandCursor = buttonMode = ((pixel >>> 24) > THRESHOLD);
|
Хорошо, часть (pixel >>> 24)
имеет смысл сейчас, но как насчет остальных?
Это просто. Мы проверяем, больше ли наш альфа-компонент (результат pixel >>> 24
), чем значение THRESHOLD
(которое в настоящее время установлено в 0). Если это так, useHandCursor
и buttonMode
установлены в true, что заставит курсор поменяться на руку. Это делает наше изображение похожим на кнопку.
Если наш альфа-компонент меньше или равен THRESHOLD
, курсор останется нормальным, поскольку мышь находится над (полупрозрачным) пикселем. Поскольку мы установили его на 0, только полностью прозрачные пиксели не будут включены как часть нашей кнопки, но вы можете установить, скажем, 0x80, и тогда он будет отображать курсор в виде руки для всего, что более чем наполовину прозрачно.
Шаг 8: прослушиватель событий CLICK
1
2
3
4
5
6
7
|
private function onClick(e:MouseEvent):void
{
if (!useHandCursor)
{
e.stopImmediatePropagation();
}
}
|
Последняя часть нашего класса BitmapButton
— слушатель событий MouseEvent.CLICK
. Эта функция будет вызываться при каждом нажатии на наше изображение, независимо от того, прозрачен этот пиксель или нет. (Изменение курсора мыши, как мы делали раньше, не повлияет на само MouseEvent
.)
Итак, каждый раз, когда происходит щелчок, мы проверяем свойство useHandCursor
. Если это true
, это означает, что мышь находится над нормальным пикселем в нашем изображении, и нам не нужно ничего делать. Это имеет смысл — событие будет продолжено до прослушивателя событий, который мы добавили в Main.as
Однако, если useHandCursor
имеет значение false, мы должны что-то сделать, чтобы событие не useHandCursor
к другим прослушивателям событий.
Для этого мы используем метод stopImmediatePropagation()
который есть у всех объектов Event
. Проще говоря, это останавливает поток событий, и слушатели событий больше его не получат. Таким образом, наша функция прослушивания событий в Main.as
никогда не будет вызываться.
Предупреждение : это может иметь неприятный побочный эффект — любой глобальный слушатель события также не получит событие. Если вас это беспокоит, попробуйте добавить строку parent.dispatchEvent(e.clone());
после e.stopImmediatePropogation()
. Хотя это выходит за рамки данного руководства, я рекомендую прочитать больше о системе событий здесь .
Вывод
Это завершает наш учебник! Спасибо за чтение, и я надеюсь, что вы узнали что-то новое.
Следует проявлять осторожность при использовании нашего класса BitmapButton
— другие MouseEvents
прежнему будут работать в обычном режиме, поскольку мы имели дело только с MouseEvent.CLICK
. Если вы хотите, вы можете использовать ту же технику, которую мы использовали для MouseEvent.CLICK
и применить ее к другим событиям, таким как MouseEvent.MOUSE_DOWN
.
Наш класс BitmapButton
позволяет нам быстро и легко создавать отличные кнопки из растровых изображений с прозрачностью, как мы делали в этой демонстрации. Если у вас есть какие-либо вопросы, я буду рад ответить на них, просто оставьте комментарий ниже.