Monthly Archive for July, 2008

Silverlight versus Flash oder ein Splash Screen ist kein Preloader!

Moderne Rich Internet Applications erreichen nicht nur eine beachtliche Funktionsvielfalt sondern auch eine durchaus spürbare Dateigröße, die das Vorausladen der Inhalte und die Visualisierung des Ladeprozesses erforderlich macht. Das ist bei Silverlight nicht anders als bei Flash. Doch Silverlight verhält sich ein wenig anders als Flash und hat auch mit „Splash Screen“ gleich einen anderen Namen dafür erhalten.

Ein Splash Screen ist kein Bestandteil der Anwendung sondern wird unabhängig als splashscreensource-Parameter des Silverlight PlugIns im HTML-Dokument gesetzt. Das hat den Vorteil, dass zu jeder Zeit ein „Preloader“ zu einer Silverlight-Anwendung hinzugefügt werden kann, ohne dass dies die eigentliche Anwendung in irgendeiner Form beeinflusst. Aber genau darin liegt auch der Nachteil: Es werden keine Ressourcen geteilt und es ist auch kein fließender Übergang vom Splash Screen zur Anwendung möglich. Sollte das erforderlich sein, dann ist ein „Stub Loader“, also eine möglichst kleine Anwendung erforderlich, die sich explizit um das Nachladen der dann vermutlich Bandbreiten verschlingenden Reste kümmert. Dieses Verfahren mit einer möglichst leichtgewichtigen Startanwendung ist so übrigens auch in der Flash-Welt durchaus gängig! Für einfache Anforderungen ist aber der Splash Screen nützlich und außerdem leicht implementiert.

Die Angabe der von Silverlight zu nutzenden XAML-Datei (keine XAP-Datei sondern wie bei Silverlight 1 ein XAML-Dokument) sowie die zugehörigen optionalen Ereignis-Handler für den Ladefortschritt (onSourceDownloadProgressChanged) und den Abschluss des Ladevorgangs (onSourceDownloadComplete) erfolgen im HTML-Dokument.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">
	<param name="source" value="ClientBin/Application.xap"/>
	<param name="onerror" value="onSilverlightError" />
	<param name="background" value="white" />
 
	<!-- Preloader Controller -->
	<param name="splashscreensource" value="Preloader.xaml"/>
	<param name="onSourceDownloadProgressChanged" value="onSourceDownloadProgressChanged" />
	<param name="onSourceDownloadComplete" value="onSourceDownloadComplete" />
 
	<a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
		<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
	</a>
</object>

Nun folgt der etwas mühsame Teil: Sämtliche Logik muss in profanem JavaScript wie zu Silverlight 1 Zeiten verfasst und in das HTML-Dokument integriert werden.

1
2
3
4
5
6
7
8
function onSourceDownloadProgressChanged(sender, eventArgs) {
	var percentage = eventArgs.progress;      
	// your code here
}
 
function onSourceDownloadComplete(sender, eventArgs) {
	// your code here
}

Den Rest erledigt das Silverlight PlugIn dann aber von alleine.

ActionScript 3 Preloader mit Framefactory

English: The following article describes the ActionScript 3 metadata framefactory and its usage for creating a preloader.

Deutsch: Zahlreiche Wege führen zu einer Flash-Anwendung. Und der Weg über reinen Code ganz ohne Zeitleiste erfreut sich dabei zunehmender Beliebtheit – zumal mit dem Flash Development Toolkit (FDT) und dem Flex Builder zwei Eclipse basierte Entwicklungsumgebungen bereitstehen, die dem im Flash enthaltenen Editor Lichtjahre voraus sind. Doch diese Herangehensweise hat auch ein paar Tücken. Eine davon ist der Preloader, der bei größeren Anwendungen den Ladeprozess ansprechend visualisiert.

In klassischen Flash-Anwendungen wird vielfach die Zeitleiste für den Preloader missbraucht, indem am Anfang die Wiedergabe stoppt, bis der restliche Inhalt geladen ist – dafür muss natürlich sichergestellt sein, dass so viel Inhalt wie möglich erst in den späteren Bereichen der SWF-Datei liegt (was sich übrigens gut mit dem Bandbreiten-Profiler in Flash prüfen lässt). So ganz ohne Zeitleiste klappt das mit FDT oder dem Flex Builder natürlich erst einmal nicht. Doch ein Blick in das Flex Framework zeigt, dass dort eine Lösung namens Framefactory exisitert. Denn das Metadata [Frame(factoryClass="Class")] erlaubt es, Code explizit an den Anfang der SWF-Datei zu legen und diesen z. B. für einen Preloader zu nutzen, bevor der restliche davon unabhängige Inhalt geladen wird.

1
2
3
4
5
6
7
package {
	import flash.display.MovieClip;
	[Frame(factoryClass="biz.wolter.app.manager.SystemManager")]
	[SWF(width="800", height="600", frameRate="24", backgroundColor="#999999", pageTitle="My Rich Application")]
	public class Application extends MovieClip {
	}
}

Die in der Framefactory referenzierte Klasse (hier analog zu Flex der SystemManager) enthält nun allen Code für den Preloader und die Initialisierung der Anwendung. Letzteres darf aber nicht durch eine „konkrete“ Referenzierung erfolgen, da ja dann der zugehörige Code mit dem SystemManager an den Anfang der SWF-Datei gepackt würde. Deshalb kommt hier nach einem erfolgreichen Ladevorgang die Methode getDefinitionByName zum Einsatz.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package biz.wolter.app.manager {
	import biz.wolter.app.controls.Preloader;
 
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.utils.getDefinitionByName;
 
	public class SystemManager extends MovieClip {
 
		public function SystemManager() {
			stop();
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			// Custom Preloader
			Preloader.show();
		}
 
		/*
		 * Handle the loading progress
		 */
		public function onEnterFrame(event:Event):void {
			if(framesLoaded == totalFrames) {
				stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
				Preloader.hide();
				nextFrame();
				create();
			} else {
				// nothing, cause Preloader handles itself
			}
		}
 
		/*
		 * Finally create the application
		 */
		private function create():void {
			var mainClass:Class = Class(getDefinitionByName("Application"));
			var app:Object = new mainClass();
			addChildAt(app as DisplayObject,0);
		}
	}
}

Wie erkenne ich, ob eine Schrift eingebettet ist?

English: The following article describes how you can quickly detect the usage of systemfonts or embedded fonts in AIR, Flash or Flex without the need of analysing the whole sourcecode.

Deutsch: Texte werden in Rich Applications (z. B. mit AIR, Flash oder Flex) normalerweise entweder mit Systemschriften oder durch eingebettete Schriften systemunabhängig dargestellt. Beide Varianten haben Ihre Vor- und Nachteile beispielsweise hinsichtlich Darstellungsqualität und Dateigröße. Mit bloßem Auge ist in einer fertigen Anwendung jedoch leider kaum erkennbar, um welche Variante es sich handelt. Und die Suche im Quellcode gestaltet sich oft wie die Suche nach der Nadel im Heuhaufen – gerade bei modularen Anwendungen, bei denen nachträglich geladene Inhalte auf Schriftkonturen der Hauptanwendung zurückgreifen sollten. Glücklicherweise gibt es jedoch einen kleinen Trick, der die Suche erleichtert. Denn ein weiterer wesentlicher Unterschied zwischen Systemschriften und eingebetteten Schriften ist, dass sich Systemschriften nicht transformieren lassen. Es reicht bereits aus, den betreffenden Inhalt (der Einfachheit halber am besten gleich die ganze Anwendung) minimal zu drehen (rotation) und schon werden Systemschriften nicht mehr dargestellt. Dies kann man sich somit zu Nutze machen, um bei einer vorhandenen Anwendung schnell zu erkennen, wo es sich um Systemschriften oder eingebettete Schriften handelt.