2 つのコンテンツ領域を並べて表示するタブレット アプリを想像してみてください。ディスプレイ全体に表示されるので、高さ 100%、幅 50% になります。リストを 1 つのコンテナーに追加するとします。当然、このリストはディスプレイ全体の半分のスペースを消費します。
さて、私の問題ですが、このサイズのリストでは高フレームレートのスクロールが不可能になる可能性はありますか? 私は最も基本的な AS3 ItemRenderer を持っていますが、スクロール中に 30fps を超えるものはまだ得られません。ここで奇妙なことに、他のコンテナーに何かを追加すると、別のリストや他のコンポーネントを言うと、リストのスクロール パフォーマンスが 20 代前半に低下します。そのため、MAX ショーでアドビの広告が表示される 40+ fps にはほど遠いです。
私は iPad2 と 3 でテストしていますが、静的な値を使用しても、スクロールはあまり良くありません。ItemRenderer のset data
メソッドが呼び出されるようにストリーミング値を有効にすると、フレームレートがさらに 2 ~ 3 フレーム低下します。
私の(ほぼ)完全なレンダラーは次のようになりますが、単一のテキストフィールドを表示するだけにそれを取り除いても、で行われているものを無効にしset data
、単一のテキストフィールドのサイズのみを設定してもlayoutContents
、パフォーマンスは説明どおりで、約30ですリストが単独で表示されている場合は、他のものも表示されている場合は 20 秒未満です。
//FCStyleableTextField is just a StyleableTextField with an additional ID
private var _textFields:Vector.<FCStyleableTextField>;
private var _oldValues:Dictionary;
private var _sym:Symbol;
public function GridRenderer() {
super();
_textFields = new Vector.<FCStyleableTextField>();
_oldValues = new Dictionary();
}
override protected function createChildren():void {
var _symLabel:FCStyleableTextField = new FCStyleableTextField();
_symLabel.editable = false;
_symLabel.selectable = false;
_symLabel.multiline = false;
_symLabel.id="sym";
_symLabel.setStyle("fontSize", fontSize);
_symLabel.textColor = 0xc0c0c0;
_textFields.push(_symLabel);
addChild(_symLabel);
var fidLen:int = fids.length;
for (var i:int = 0; i<fidLen; i++) {
var _fid_lbl:FCStyleableTextField = new FCStyleableTextField();
_fid_lbl.selectable = false;
_fid_lbl.editable = false;
_fid_lbl.multiline = false;
_fid_lbl.id = String(fids[i]);
_fid_lbl.textColor = 0xc0c0c0;
_fid_lbl.setStyle("textAlign", "right");
_fid_lbl.setStyle("fontSize", fontSize);
_fid_lbl.text = " ";
_textFields.push(_fid_lbl);
addChild(_fid_lbl);
if(i>visibleColumns) {
_fid_lbl.includeInLayout = false;
_fid_lbl.visible = false;
}
}
}
override public function set data(value:Object):void {
if(!value) return;
if(data) {
// check if the value's symbolName is different than the current
// data's symbolName, if so, the itemRenderer has been
// recycled, thus we need to reset the old fid values
if((value as Symbol).symbolName != (data as Symbol).symbolName)
_oldValues = new Dictionary();
}
super.data = value;
_sym = data as Symbol;
try {
var textLen:int = _textFields.length;
for (var i:int = 0; i<textLen;i++) {
var lbl:FCStyleableTextField = _textFields[i];
if(lbl.id == "sym") {
lbl.text = _sym.symbolName;
lbl.truncateToFit();
} else {
if(lbl.id == _sym.fidList.fidMap[lbl.id].fidId && lbl.text != _sym.fidList.fidMap[lbl.id].fieldValue) {
var time:int = new Date().time;
var timerName:String = _sym.symbolName+","+lbl.id+","+grid;
globalTimer.addTimer(timerName, time, "reset", lbl, null, null);
var _oldVal:* = _oldValues[lbl.id];
var _newVal:* = _sym.fidList.fidMap[lbl.id].fieldValue;
// basic color formatting
if(Number(_newVal) > Number(_oldVal))
lbl.textColor = 0x40c040;
else if(Number(_newVal) < Number(_oldVal))
lbl.textColor = 0xf05050;
// add + to change and changePercent fids if value is positive
if(lbl.id == "56") {
if(_newVal >0)
lbl.text = "+" + _newVal;
else
lbl.text = String(_newVal);
} else if(lbl.id == "11") {
if(_newVal >0)
lbl.text = "+" + _newVal;
else
lbl.text = String(_newVal);
} else
lbl.text = String(_newVal);
if(!_sym.fidList.fidMap[lbl.id].fieldValue)
lbl.text =" ";
_oldValues[lbl.id] = _newVal;
}
}
lbl.truncateToFit();
}
} catch (e:Error) { /* nothing to do here -> try/catch required due to async symbolassembly */ }
}
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void {
var viewWidth:Number = unscaledWidth - paddingLeft - paddingRight;
var viewHeight:Number = unscaledHeight - paddingTop - paddingBottom;
var _previousLabel:FCStyleableTextField;
var textLen:int = _textFields.length;
for(var i:int =0; i<textLen;i++) {
var lbl:FCStyleableTextField = _textFields[i];
graphics.beginFill(0x808080, .3);
lbl.height = viewHeight;
lbl.y = paddingTop;
if(lbl.id=="sym") {
lbl.width = 95;
} else if (lbl.id == "35000") {
lbl.width = 24;
} else {
lbl.width = optimalColWidth;
}
_previousLabel ? lbl.x = (_previousLabel.x + _previousLabel.width): lbl.x = paddingLeft;
graphics.drawRect(lbl.x+lbl.width, 1, 1, unscaledHeight-1);
lbl.commitStyles();
_previousLabel = lbl;
graphics.endFill();
}
}
それでも、速度低下の原因はアイテム レンダラーではないことは確かです。先ほど述べたように、テキスト フィールドを 1 つだけ表示するレンダラーと比較して、2 フレーム、おそらく 3 フレームのコストがかかるからです。むしろ、一度に表示されるベクトルの量を Flex がどうにか処理できないと思いますが、そのようなことは可能ですか? また、パフォーマンスを向上させる方法はありますか? ユーザーがリストをスクロールするとすぐにライブ ストリーミングの値を無効にしたので、Flex は基本的にビットマップをスクロールするだけで済みます (LabelItemRenderer が自動的に有効になるためcacheasbitmap
) が、おそらく 4 フレーム増加しました。スクロールを少しスムーズにするコツは何ですか?