Представьте себе приложение для планшета, в котором две области содержимого отображаются рядом. Они полностью заполняют экран, поэтому их высота составляет 100%, а ширина - 50%. Предположим, мы добавляем список в один контейнер. Естественно, этот список будет занимать половину всего экрана.
Теперь к моей проблеме, возможно ли, что прокрутка с высокой частотой кадров невозможна со списками такого размера? У меня самый простой AS3 ItemRenderer, и я по-прежнему не могу получить более 30 кадров в секунду во время прокрутки. Теперь странная часть, если я добавлю что-то в другой контейнер, скажем, другой список или другие компоненты, производительность прокрутки списка упадет до 20 с. Так что и рядом с 40+ кадрами в секунду вы не видите рекламу Adobe на их шоу MAX.
Я тестирую iPad2 и 3, и даже со статическими значениями прокрутка не очень хороша. Теперь, если я включаю потоковую передачу значений и вызываю метод set data
ItemRenderer, частота кадров падает еще на 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();
}
}
Тем не менее, я почти уверен, что это не средство визуализации элементов вызывает замедление, потому что, как я уже сказал, он стоит 2, может быть, 3 кадра по сравнению с средством визуализации, которое отображает только одно текстовое поле. Я скорее думаю, что Flex почему-то не может обрабатывать количество отображаемых векторов одновременно, возможно ли что-то подобное? И есть ли способ повысить производительность? Я уже отключил значения потоковой передачи в реальном времени, как только пользователь прокручивает список, так что flex в основном просто прокручивает растровые изображения (поскольку LabelItemRenderer автоматически включает cacheasbitmap
), но это позволило получить, возможно, 4 кадра. Какие уловки, ребята, делают, чтобы прокрутка стала более плавной?