2013-07-11 4 views
2

Так как кнопка является одним из самых популярных компонентов GUI this question becomes hot, когда мы говорим о memory usage. Особенно, если у вас есть tons of buttons в вашем приложении.Самая легкая реализация кнопок в actionscript 3.0

Итак, как вы можете реализовать кнопку, которая использует minimum CPU and memory resources, и да, действует как обычная кнопка с помощью мыши вверх, вниз и ручного поведения указателя. Текст метки также необходим.

ответ

3

Если вы хотите иметь тонны кнопок с текстом и графикой, используя наименьшее количество ОЗУ и вычислительной мощности, вы должны использовать растровые изображения.

Это становится намного более сложным и включает в себя собственную подготовку следующее:

  1. шрифт в виде спрайта листа.
  2. Классы, которые управляют визуализацией текста на растровое изображение, используя этот лист спрайтов.
  3. Растровые изображения не отвечают на MouseEvents, поэтому вам нужно будет создать собственную систему для управления вводом мышей на растровых изображениях.

Во-первых, давайте взглянем на потребление базовой памяти для некоторых объектов DisplayObject, которые, по вашему мнению, нам лучше всего использовать. Это наш метод тестирования:

function ram(type:Class):void 
{ 
    trace(getSize(new type())); 
} 

И это испытание:

ram(Sprite); // 408 
ram(Shape); // 236 
ram(TextField); // 1316 

В вашем случае, рисунок 1000 кнопок приведет к более 1724000 байт памяти используется.

Теперь давайте посмотрим на то, что мы будем использовать:

  1. 1x Bitmap, действующий как Canvas, который содержит все кнопки: 236 байт.
  2. 1x BitmapData, представляющий начальное состояние каждой кнопки.
  3. 1x BitmapData, представляющий состояние опрокидывания каждой кнопки.
  4. 1x BitmapData сохраняет наш текст как лист спрайта для использования всеми кнопками.

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

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

Вот класс Button:

public class BitmapButton 
{ 

    private var _text:String; 
    private var _position:Point = new Point(); 


    public function BitmapButton(text:String) 
    { 
     _text = text; 
    } 


    public function render(canvas:BitmapData, font:BitmapData, state:BitmapData):void 
    { 
     canvas.copyPixels(state, state.rect, _position); 

     // Use font argument to render text. 
     // For you to implement. 
    } 


    public function get position():Point{ return _position; } 

} 

А вот класс, который будет управлять рендеринга этих кнопок:

public class ButtonCanvas extends Bitmap 
{ 

    private var _fontSprite:BitmapData; 
    private var _baseState:BitmapData = new BitmapData(100, 30, false, 0xFF0000); 
    private var _overState:BitmapData = new BitmapData(100, 30, false, 0x00FF00); 
    private var _buttons:Vector.<BitmapButton> = new <BitmapButton>[]; 
    private var _checkRect:Rectangle = new Rectangle(); 


    public function ButtonCanvas(width:int, height:int) 
    { 
     bitmapData = new BitmapData(width, height, true, 0x00000000); 

     // Replace with actual loaded sprite sheet. 
     _fontSprite = new BitmapData(1, 1); 
    } 


    public function add(button:BitmapButton):void 
    { 
     _buttons.push(button); 
    } 


    public function render():void 
    { 
     if(stage === null) return; 

     bitmapData.lock(); 
     for each(var i:BitmapButton in _buttons) 
     { 
      _checkRect.x = i.position.x; 
      _checkRect.y = i.position.y; 
      _checkRect.width = _baseState.width; 
      _checkRect.height = _baseState.height; 

      if(_checkRect.contains(mouseX, mouseY)) 
      { 
       // Use roll over style. 
       // Need to implement depth check so you can't roll over buttons 
       // that fall behind others. 
       i.render(bitmapData, _fontSprite, _overState); 
      } 
      else 
      { 
       i.render(bitmapData, _fontSprite, _baseState); 
      } 
     } 

     bitmapData.unlock(); 
    } 


    public function get buttons():Vector.<BitmapButton>{ return _buttons; } 

} 

и небольшой тест:

var canvas:ButtonCanvas = new ButtonCanvas(stage.stageWidth, stage.stageHeight); 
addChild(canvas); 


for(var i:int = 0; i < 20; i++) 
{ 
    var button:BitmapButton = new BitmapButton("Hello"); 
    button.position.x = Math.random() * stage.stageWidth; 
    button.position.y = Math.random() * stage.stageHeight; 
    canvas.add(button); 
} 


stage.addEventListener(MouseEvent.MOUSE_MOVE, update); 
function update(e:MouseEvent):void 
{ 
    canvas.render(); 
} 

canvas.render(); 

Теперь, когда вы» я прочитал все это, я укажу, что это действительно маловероятно y ou нужно в любом месте рядом с этой экстрим, если у вас нет какой-либо игры, которая вращается вокруг кнопок и кнопок на самом деле частицы, которые генерируют каждый кадр в 100-х годах. Использование стандартного Sprite + TextField отлично подходит практически во всех случаях.

+0

В вашем случае при рисовании 1000 кнопок будет получено более 1 724 000 байт - почему? Если я использую только текстовое поле, это будет 1,316,000. Но человек, это очень интересно. Не могли бы вы подробнее рассказать о функции getSize()? – ZuzEL

+0

@ZuzEL Потому что вам нужно определить новый Sprite и TextField для каждой кнопки. В моем примере вам нужно только определить новый экземпляр «BitmapButton», который очень легкий. Кроме того, 'getSize()' сообщает вам, сколько памяти использует объект. – Marty

+0

Мне не нужен Sprite в моем примере – ZuzEL

0

рискну сказать sprite с набором buttonMode собственности на true для «ручного указателя» и затем функции для выполнения ROLL_OVER и ROLL_OUT MouseEvents.

+0

Это самый популярный способ сделать это, спасибо! Но зачем вам слушать события ROLL_OVER и ROLL_OUT, если у вас уже установлен параметр buttonMode равным true? Я думаю, вы имели в виду MOUSE_UP и MOUSE_DOWN. Вы? – ZuzEL

+0

Извините, я неправильно понял ваше требование «мышь вверх, вниз и указатель руки». Когда вы наводите курсор на кнопку, Rolls должны увидеть графическое изменение кнопки. Я предполагаю, что это функционально то же самое, что и ручной указатель, указывающий на то, что мышь находится над кнопкой, но она красивее. –

1

Одним из традиционных моделей использует Sprite + TextField

Adobe рекомендует использовать Shape вместо Sprite (когда это имеет смысл):

объект Sprite является контейнером экранного объекта, тогда как объект Shape является не. По этой причине объекты Shape потребляют меньше памяти, чем объекты Sprite, которые содержат одну и ту же графику.

Было бы здорово использовать Shape, и мы можем это сделать, но мы не можем добавить TextField.

Теперь давайте посмотрим на TextField наследования цепи:

TextField: InteractiveObject -> DisplayObject -> EventDispatcher -> Объект

Мы можем заметить, что объект TextField намного легче, чем Sprite объект - неправильный. Использование только TextField будет легче, чем использование TextField + Sprite. Я пришел с этим решением:

import flash.events.MouseEvent; 
import flash.filters.BevelFilter; 
import flash.text.TextField; 
import flash.text.TextFormat; 
import flash.ui.Mouse; 
import flash.ui.MouseCursor; 

public class Button extends TextField 
{ 
    private static const MOUSE_UP:Array = 
    [new BevelFilter(2, 45, 0xEEEEEE, .7, 0x444444, .7, 1, 1)]; 

    private static const MOUSE_DOWN:Array = 
    [new BevelFilter(2, 225, 0xEEEEEE, .7, 0x444444, .7, 1, 1)]; 

    private static const TEXT_FORMAT:TextFormat = 
    new TextFormat('Verdana', 12, 0xDDDDDD, 
    null, null, null, null, null, 'center'); 

    public function Button(label:String, color:int = 0x166488) 
    { 
     width = 80; 
     height = 20; 
     background = true; 
     backgroundColor = color; 
     selectable = false; 
     defaultTextFormat = TEXT_FORMAT; 

     text = label; 
     addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); 
     addEventListener(MouseEvent.MOUSE_UP, onMouseUp); 
     addEventListener(MouseEvent.ROLL_OVER, onMouseRollOver); 
     addEventListener(MouseEvent.ROLL_OUT, onMouseRollOut); 
     onMouseUp(); 
    } 

    private function onMouseRollOut(e:MouseEvent):void 
    { 
     Mouse.cursor = MouseCursor.AUTO; 
    } 

    private function onMouseRollOver(e:MouseEvent):void 
    { 
     Mouse.cursor = MouseCursor.BUTTON; 
    } 

    private function onMouseDown(e:MouseEvent):void 
    { 
     filters = MOUSE_DOWN; 
    } 

    private function onMouseUp(e:MouseEvent = null):void 
    { 
     filters = MOUSE_UP; 
    } 
    //kill method 
} 

Generated button

Этот код рисует красивую легкую кнопку НО Я не могу настроить вертикальное положение текста этикетки, чтобы высота этой кнопки зависит от размера шрифта. Другая проблема заключается в том, что я не могу переместить текстовую метку немного вниз, когда кто-то нажимает на нее.

Любые идеи будут оценены.

+2

'Мы можем заметить, что объект TextField намного легче объекта Sprite. Это совершенно неверно. «Sprite» использует 408 байт в памяти, тогда как «TextField» использует 1316. – Marty

1

Мы можем заметить, что объект TextField намного легче объекта Sprite. Это совершенно неверно. Sprite использует 408 байт в памяти, тогда как TextField использует 1316

Да TextField будет потреблять больше памяти.

Я бы создал текст метки в графической программе и создал класс меню спрайтов.

TextField не очень легкий, но довольно мощный класс. Если вам нужен пользовательский ввод, то TextField - это путь.

Избегайте любых кнопок, встроенных в библиотеку Flash, и просто начинайте простую и строящую функциональность класса спрайтов.

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

Сделать функцию, которая вызывается каждый кадр, tick() ;, think() ;, update(); что-то вроде этого. Добавьте один обработчик события в основной класс и внутри него вызовите функцию update() в элементах меню.

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

Смежные вопросы