Renderowanie obiektów tekstowych

W celu zwiększenia wydajności renderowania tekstu należy użyć buforowania bitmapy i właściwości opaqueBackground .

Mechanizm Flash Text Engine oferuje pewnie znaczące optymalizacje. Jednak do wyświetlenia pojedynczego wiersza tekstu użyć trzeba wielu różnych klas. Dlatego do utworzenia edytowalnego pola tekstowego za pomocą klasy TextLine wymagana jest duża ilość pamięci i wiele wierszy kodu ActionScript. Klasa TextLine najlepiej nadaje się do obsługi statycznego tekstu niedostępnego do edycji — zapewnia wówczas szybsze renderowanie i wymaga mniejszej ilości pamięci.

Funkcja buforowania bitmapy umożliwia buforowanie treści wektorowych jako bitmap w celu zwiększenia wydajności renderowania. Ta funkcja jest użyteczna w przypadku złożonych treści wektorowych, a także gdy jest używana z tekstem, którego renderowanie wymaga przetwarzania.

Poniższy przykład przedstawia, w jaki sposób można wykorzystać funkcję buforowania bitmapy i właściwość opaqueBackground do przyspieszenia renderingu. Poniższy rysunek przedstawia typowy ekran powitalny, który może zostać wyświetlony, gdy użytkownik oczekuje na załadowanie treści:

Powiększ obraz
Ekran powitalny

Poniższy rysunek ilustruje programową zmianę dynamiki zastosowaną do obiektu TextField. Tekst jest powoli, niejednostajnie przemieszczany od góry do środka sceny:

Powiększ obraz
Dynamiczny niejednostajny ruch tekstu

Poniższy kod generuje efekt dynamicznego niejednostajnego ruchu tekstu. Zmienna preloader zawiera bieżący obiekt docelowy, co ogranicza wyszukiwanie właściwości, które może znacznie zmniejszać wydajność:

wait_mc.addEventListener( Event.ENTER_FRAME, movePosition ); 
  
var destX:Number=stage.stageWidth/2; 
var destY:Number=stage.stageHeight/2; 
var preloader:DisplayObject; 
  
function movePosition( e:Event ):void 
{ 
    preloader = e.currentTarget as DisplayObject; 
     
    preloader.x -= ( preloader.x - destX ) * .1; 
    preloader.y -= ( preloader.y - destY ) * .1; 
     
    if (Math.abs(preloader.y-destY)<1) 
        preloader.removeEventListener( Event.ENTER_FRAME, movePosition ); 
}

Funkcja Math.abs() może zostać umieszczona w tym miejscu kodu w celu zmniejszenia liczby wywołań funkcji i dodatkowego zwiększenia wydajności. Dobrą praktyką jest zastosowanie typu int dla właściwości destX i destY , dzięki czemu dostępne będą wartości stałopozycyjne. Stosowanie typu int umożliwia uzyskanie idealnego przyciągania do pikseli bez konieczności ręcznego zaokrąglania wartości za pomocą powolnych metod, takich jak Math.ceil() i Math.round() . Ten kod nie zaokrągla współrzędnych do int, ponieważ ciągłe zaokrąglanie wartości powoduje, że obiekt nie porusza się płynnie. Ruchy obiektu mogą być drżące, ponieważ współrzędne są przyciągane do najbliższych zaokrąglonych liczb całkowitych w każdej klatce. Jednak ta technika może być użyteczna w przypadku ustawiania końcowego położenia obiektu wyświetlanego. Nie należy stosować poniższego kodu:

// Do not use this code 
var destX:Number = Math.round ( stage.stageWidth / 2 );  
var destY:Number = Math.round ( stage.stageHeight / 2); 

Poniższy kod działa znacznie szybciej:

var destX:int = stage.stageWidth / 2;  
var destY:int = stage.stageHeight / 2; 

Poprzedni kod można dodatkowo zoptymalizować poprzez użycie operatorów bitowych do dzielenia wartości:

var destX:int = stage.stageWidth >> 1;  
var destY:int = stage.stageHeight >> 1;

Funkcja buforowania bitmapy ułatwia środowisku wykonawczemu renderowanie obiektów przez stosowanie dynamicznych bitmap. W bieżącym przykładzie zilustrowano buforowanie klipu filmowego zawierającego obiekt TextField:

wait_mc.cacheAsBitmap = true;

Dodatkowym sposobem na zwiększenie wydajności jest usunięcie przezroczystości (alfa). Przezroczystość alfa wymaga dodatkowych obliczeń w środowisku wykonawczym podczas rysowania obrazów przezroczystych bitmap, co zademonstrowano w poprzednim przykładowym kodzie. Korzystając z właściwości opaqueBackground , można pominąć rysowanie poprzez określenie koloru jako tła.

W przypadku korzystania z właściwości opaqueBackground powierzchnia bitmapy utworzona w pamięci nadal wykorzystuje 32 bity. Jednak przesunięcie wartości alfa jest ustawione na 255 i nie jest wykorzystywana przezroczystość. W rezultacie właściwość opaqueBackground nie zmniejsza obciążenia pamięci, ale zwiększa wydajność renderowania w przypadku korzystania z buforowania bitmapy. W poniższym kodzie zastosowano wszystkie techniki optymalizacji:

wait_mc.addEventListener( Event.ENTER_FRAME, movePosition ); 
wait_mc.cacheAsBitmap = true; 
  
// Set the background to the color of the scene background 
wait_mc.opaqueBackground = 0x8AD6FD; 
var destX:int = stage.stageWidth >> 1; 
var destY:int = stage.stageHeight >> 1; 
var preloader:DisplayObject; 
  
function movePosition ( e:Event ):void 
{ 
    preloader = e.currentTarget as DisplayObject; 
     
    preloader.x -= ( preloader.x - destX ) * .1; 
    preloader.y -= ( preloader.y - destY ) * .1; 
     
    if ( Math.abs ( preloader.y - destY ) < 1 ) 
        e.currentTarget.removeEventListener ( Event.ENTER_FRAME, movePosition ); 
}

Zoptymalizowano animację i buforowanie bitmapy poprzez usunięcie przezroczystości. Rozważmy zmianę jakości stołu montażowego na LOW i HIGH na urządzeniach przenośnych, w różnych stanach animacji i podczas korzystania z funkcji buforowania bitmapy:

wait_mc.addEventListener( Event.ENTER_FRAME, movePosition ); 
wait_mc.cacheAsBitmap = true; 
wait_mc.opaqueBackground = 0x8AD6FD; 
  
// Switch to low quality 
stage.quality = StageQuality.LOW; 
var destX:int = stage.stageWidth>>1; 
var destY:int = stage.stageHeight>>1; 
var preloader:DisplayObject; 
  
function movePosition( e:Event ):void 
{ 
    preloader = e.currentTarget as DisplayObject; 
     
    preloader.x -= ( preloader.x - destX ) * .1; 
    preloader.y -= ( preloader.y - destY ) * .1; 
     
    if (Math.abs(e.currentTarget.y-destY)<1) 
    { 
        // Switch back to high quality 
        stage.quality = StageQuality.HIGH; 
        preloader.removeEventListener( Event.ENTER_FRAME, movePosition ); 
    } 
}

W tym przypadku zmiana jakości stołu montażowego zmusza środowisko wykonawcze do ponownego wygenerowania bitmapy powierzchni obiektu TextField w celu zapewnienia jej zgodności z aktualną jakością obiektu Stage (stołu montażowego). Z tego powodu zmiana jakości stołu montażowego nie jest zalecana, gdy używana jest funkcja buforowania bitmapy.

W tym przypadku możliwe jest także zastosowanie ręcznego buforowania bitmapy. W celu zasymulowania działania właściwości opaqueBackground klip filmowy można rysować w nieprzezroczystym obiekcie BitmapData, przez co środowisko wykonawcze nie będzie musiało ponownie generować bitmapy powierzchni.

Ta technika przynosi dobre rezultaty, pod warunkiem że treść nie ulega zmianie w miarę upływu czasu. Jeśli jednak treść pola tekstowego może ulec zmianie, należy rozważyć zastosowanie innej strategii. Wyobraźmy sobie na przykład pole tekstowe, w którym ciągle zmieniana jest wartość procentowa obrazująca postęp ładowania aplikacji. Jeśli to pole tekstowe (lub zawierający je obiekt wyświetlany) zostało zbuforowane jako bitmapa, jego powierzchnia musi zostać wygenerowana przy każdej zmianie zawartości pola. Nie można zastosować ręcznego buforowania bitmapy, ponieważ zawartość obiektu wyświetlanego nieustannie się zmienia. Zmiana tej stałej mogłaby wymusić ręczne wywołanie metody BitmapData.draw() w celu zaktualizowania buforowanej bitmapy.

Należy pamiętać o tym, że począwszy od programu Flash Player 8 (i środowiska AIR 1.0) — bez względu na jakość stołu montażowego — pole tekstowe z opcją renderowania Wygładź dla czytelności pozostaje idealnie wygładzone. Takie rozwiązanie zmniejsza zużycie pamięci, ale powoduje większe obciążenie procesora, a rendering przebiega nieznacznie wolniej niż w przypadku funkcji buforowania bitmapy.

W poniższym kodzie zastosowano takie rozwiązanie:

wait_mc.addEventListener( Event.ENTER_FRAME, movePosition ); 
  
// Switch to low quality 
stage.quality = StageQuality.LOW; 
var destX:int = stage.stageWidth >> 1; 
var destY:int = stage.stageHeight >> 1; 
var preloader:DisplayObject; 
function movePosition ( e:Event ):void 
{ 
    preloader = e.currentTarget as DisplayObject; 
     
    preloader.x -= ( preloader.x - destX ) * .1; 
    preloader.y -= ( preloader.y - destY ) * .1; 
     
    if ( Math.abs ( preloader.y - destY ) < 1 ) 
    { 
        // Switch back to high quality 
        stage.quality = StageQuality.HIGH; 
        preloader.removeEventListener ( Event.ENTER_FRAME, movePosition ); 
    } 
}

Stosowanie tej opcji (Wygładź dla czytelności) w odniesieniu do tekstu w ruchu nie jest zalecane. W przypadku skalowania tekstu ta opcja powoduje podejmowanie prób zachowania wyrównania tekstu, co wywołuje efekt przesuwania. Jeśli zawartość obiektu wyświetlanego jest stale zmieniana, a wymagany jest tekst skalowany, można zwiększyć wydajność aplikacji dla urządzeń przenośnych przez ustawienie jakości LOW . Po zakończeniu ruchu można z powrotem przywrócić jakość HIGH .