3

我目前正在开发一个以 iPad2 作为硬件平台的 Adob​​e AIR 应用程序,并且无法在其中一个屏幕上获得不错的滚动性能。我正在使用一个火花列表,带有一个像这样的自定义项目渲染器:

<s:List id="productList" top="116" bottom="0" left="10" right="10" 
    width="100%"
    visible="true" includeInLayout="true"
    height="0"
    maxHeight="500"
    opaqueBackground="#ffffff"
    itemRenderer="myRenderer">
</s:List>

最初,我使用的是 .mxml 渲染器,但在看到令人讨厌的性能后,我决定自己动手,扩展 UIComponent(我已经放弃了包和大括号以节省水平空间):

import mx.controls.listClasses.IListItemRenderer;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.utils.ColorUtil;

import spark.components.Label;
import spark.components.TextInput;

public final class OrderViewProductLineTestIR extends UIComponent implements IListItemRenderer 
{
    public function OrderViewProductLineTestIR()
    {
        super();
    }

    // Internal variable for the property value.
    private var _data:Object;

    private var productName:Label;
    private var orderQty:TextInput;
    private var stockQty:TextInput;


    // Make the data property bindable.
    [Bindable("dataChange")]

    // Define the getter method.
    public function get data():Object
    {
        return _data;
    }

    // Define the setter method, and dispatch an event when the property
    // changes to support data binding.
    public function set data(value:Object):void
    {
        _data = value;
        invalidateProperties();
        dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
    }

    override protected function createChildren():void
    {
        super.createChildren();

        productName = new Label();
        // productName.visible = true;
        addChild(productName);

        orderQty = new TextInput();
        addChild(orderQty);

        stockQty = new TextInput();
        addChild(stockQty);

    }

    override protected function commitProperties():void
    {
        super.commitProperties();
        productName.text = _data.Name;
    }

    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        productName.move(0, 0);
        productName.setActualSize(250, 48);

        orderQty.move(270, 0);
        orderQty.setActualSize(100, 48);

        stockQty.move(390, 0);
        stockQty.setActualSize(100, 48);
    }

    override protected function measure():void
    {
        super.measure();

        measuredWidth = 490;
        measuredHeight = 48; 
    }
}

正如您所看到的,这是非常轻量级的,但我的数据提供程序包含超过 100 个项目,其中 11 个可以随时显示在屏幕上。我所读到的关于提高滚动性能的所有内容都围绕着使用opaqueBackgroundand cacheAsBitmap,但是无论我尝试什么,这里都没有帮助。在列表级别使用cacheAsBitmap并没有帮助,因为一旦您滚动了超过几行需要重新渲染整个内容的项目渲染器回收,并且在项目渲染器级别使用它仍然非常慢快速滚动——大概是因为在非常快速的滚动过程中同时回收了许多。

我知道 iPad 以 60 fps 在一帧中传送一屏信息应该没有问题,但是当我快速滚动时,我发现它很难达到 10 fps(从视线中)。所以问题是:我是否遗漏了一些明显的东西,或者这是由于使用 AIR 时涉及的层数(和矢量渲染)而可以预料到的?作为记录,我尝试更改应用程序的渲染模式并尝试更改帧速率以消除明显的问题。

4

3 回答 3

0

这个有点猜,但是itemRenderer能优化吗?每次重绘组件时,是否需要对所有子元素进行定位和调整大小?每次 commitProperties 运行时都需要更新 productName.text 吗?

以下是我可以修改的方法:

import mx.controls.listClasses.IListItemRenderer;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.utils.ColorUtil;

import spark.components.Label;
import spark.components.TextInput;

public final class OrderViewProductLineTestIR extends UIComponent implements IListItemRenderer 
{
    public function OrderViewProductLineTestIR()
    {
        super();
    }

    // Internal variable for the property value.

private var _data:Object;

// Add a dataChanged property 
private var dataChanged :Boolean = false

private var productName:Label;
private var orderQty:TextInput;
private var stockQty:TextInput;


// Make the data property bindable.
[Bindable("dataChange")]

// Define the getter method.
public function get data():Object
{
    return _data;
}

// Define the setter method, and dispatch an event when the property
// changes to support data binding.
public function set data(value:Object):void
{
    _data = value;
    // switch the dataChanged flag 
    dataChanged = true;
    invalidateProperties();
    dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}

override protected function createChildren():void
{
    super.createChildren();

    productName = new Label();
    // productName.visible = true;
    addChild(productName);

    orderQty = new TextInput();
    addChild(orderQty);

    stockQty = new TextInput();
    addChild(stockQty);

}

override protected function commitProperties():void
{
    super.commitProperties();
    // Only update the display if the data actually changed 
    If(dataChanged){
      productName.text = _data.Name;
      dataChanged = false;
    }
}


// add variable to tell whether the component's children have been sized and positioned or not
// since they have static locations, no need to set these each time
protected var compChildrenSized :Boolean = false;
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    super.updateDisplayList(unscaledWidth, unscaledHeight);
    if(!compChildrenSized){
     productName.move(0, 0);
     productName.setActualSize(250, 48);

     orderQty.move(270, 0);
     orderQty.setActualSize(100, 48);

     stockQty.move(390, 0);
     stockQty.setActualSize(100, 48);

     compChildrenSized = true;
    }
}

override protected function measure():void
{
    super.measure();

    measuredWidth = 490;
    measuredHeight = 48; 
}
}

我想我会补充一点,我不确定措施是否会运行。如果用标签替换 textInputs 会发生什么?您使用的是 Flex 4.6,如果是,您使用的是 StyleableStageText(AKA StageText)还是使用 StyleableTextField 的 4.5 皮肤?我想知道 StageText 滚动是否会因为它挂在 Flash 显示列表上方而降低性能。

如果您完全删除 textInput 并替换为标签会发生什么?

这些都是小事,我不确定它们是否会有所帮助。

于 2012-04-17T10:54:36.203 回答
0

在您的“Spark List 组件”上尝试此操作
1/ 添加布局(水平或垂直,取决于您想要什么;)
2/ 在您的列表组件上添加属性“useVirtualLayout=true”!

并告诉我结果是什么......但我认为它会更平滑(非常非常平滑),因为当你将元素添加到列表时,所有组件都会被渲染,即使它们不在布局中......所以“useVirtualLayout”只是在视口上的项目被渲染,其他项目被破坏......

见!并享受 Flash Builder 的乐趣!拥有多支持应用程序是一项非常酷的技术!

于 2012-04-24T22:43:23.857 回答
-1

有点晚了。但。

确实,如果您想要接近原生性能的东西,最好使用八哥和羽毛。

但是你仍然可以优化你的渲染器。请不要在 Flex 移动应用程序的任何地方使用绑定。扩展 UIComponent 是正确的做法。我认为最好不要使用失效并在数据设置器中设置您的属性。

希望能帮助到你。

于 2014-02-07T22:03:19.627 回答