2

this question becomes hot由于按钮是我们谈论时最流行的 GUI 组件之一memory usage。特别是当你tons of buttons在你的应用程序中。

那么如何实现一个按钮,它使用minimum CPU and memory resources是的,就像普通按钮一样,实现了鼠标向上、向下和手指针行为。标签文本也是必需的。

4

4 回答 4

3

如果您想拥有大量带有文本和图形的按钮,使用最少的 RAM 和处理能力,您应该使用位图。

这变得更加复杂,并且需要您自己准备以下内容:

  1. 精灵表形式的字体。
  2. 使用该精灵表管理将文本渲染到位图的类。
  3. 位图不响应 MouseEvents,因此您需要构建自己的系统来管理位图上的鼠标输入。

首先,让我们看一下您认为我们最适合使用的一些 DisplayObject 的基本内存消耗。这是我们的测试方法:

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

这是测试:

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

在您的情况下,绘制 1000 个按钮将导致使用超过 1,724,000 字节的内存。

现在让我们看看我们将使用什么:

  1. 1x 位图充当包含所有按钮的画布:236 字节。
  2. 1x BitmapData 表示每个按钮的初始状态。
  3. 1x BitmapData 表示每个按钮的翻转状态。
  4. 1x BitmapData 将我们的文本存储为精灵表,供所有按钮使用。

每个BitmapData都会消耗相当大的内存,并且根据其内容而有很大差异。但这里的诀窍是我们只使用一个,并为我们想要绘制的每个按钮引用它的内容。

我已经设置了少量代码来帮助您入门。您仍然需要实现一个点击管理器,它循环遍历所有按钮并找出与触发点击最相关的按钮,并在按钮上呈现文本。

这是按钮类:

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();

既然您已经阅读了所有这些内容,我将指出您实际上不太可能需要接近这个极端,除非您有某种类型的游戏围绕按钮和按钮实际上是在每一帧中生成的粒子100 的。在几乎所有情况下,使用标准 Sprite + TextField 都非常好。

于 2013-07-11T23:16:45.650 回答
1

我们可以观察到 TextField 对象比 Sprite 对象轻得多。这是完全不正确的。Sprite 在内存中使用 408 字节,而 TextField 使用 1316

是的 TextField 会消耗更多的内存。

我会在图形程序中创建标签文本并创建一个精灵菜单类。

TextField 并不是真正的轻量级,而是一个非常强大的类。如果您想要用户输入,那么 TextField 是要走的路。

避免使用 Flash 库中内置的任何按钮,只需开始简单并在 sprite 类上构建功能。

如果您真的想优化您的界面,请减少事件处理程序和任何类型的透明度。一般来说,这可能只是很好的 Flash 建议,但经常被忽视。

制作一个每帧都调用的函数,tick();, think();, update(); 像这样的东西。将单个事件处理程序添加到主类并在菜单元素中调用您的 update() 函数。

向菜单元素添加十几个事件处理程序不仅麻烦而且难看。

于 2013-07-13T12:14:31.210 回答
1

传统模式之一是使用Sprite + TextField

Adobe 建议使用 Shape 而不是 Sprite(当它有意义时):

Sprite 对象是显示对象容器,而 Shape 对象不是。因此,Shape 对象比包含相同图形的 Sprite 对象消耗更少的内存。

使用 Shape 会很棒,我们可以做到,但我们不能在其上添加 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
}

生成的按钮

此代码绘制了漂亮的轻量级按钮,我无法调整文本标签的垂直位置,因此此按钮的高度取决于字体大小。另一个问题是,当有人单击它时,我无法将文本标签向右下方移动。

任何想法将不胜感激。

于 2013-07-11T21:31:37.980 回答
0

我敢说一个sprite属性buttonMode设置为“手形指针” ,true然后处理鼠标事件。ROLL_OVERROLL_OUT

于 2013-07-11T20:51:22.630 回答