Minigolf in Serienbild

Eine tolle Gelegenheit zwei Sachen auf einmal zu zeigen: Einerseits den Mini(atur)golfgewinner Jubel von gestern und anderseits eine Software die “interaktiv” Serienbilder anzeigen kann (ab Flash Player 9):

 

Hier die Platzierungen:
Marian als Sieger (39er Runde), Arndt belegt den zweiten Platz (42er Runde), Ich als Dritter (46er Runde) und auf den Plätzen (und leider nicht auf dem Siegerfoto) Christian (52erRunde) und Paul (54er Runde).

Na gut, Christian ist irgendwie doch auf den Siegerfotos :)

Adobe Flex: ItemRenderer…

In jeder Programmiersprache und jedem Framework gibt es verschiedene Wege zum Ziel zu kommen. Einmal der Quick und Dirty Weg, der auf dem “HighEnd Entwickler System” gut funktioniert aber in der Realwelt Unzufriedenheit hervorruft, und (neben weiteren) den Weg das gleiche Ziel Ressourcen schonend umzusetzen.

So geschehen beim itemRenderer im PZ Projekt.

Eine TileList soll Bilder anzeigen und zwar eine Menge.

Quick N’ Dirty: Als itemRenderer habe ich eine Komponente auf Basis der Canvas gebaut in der ein Bild liegt. Das funktioniert wunderbar und sieht gut aus, doch ein schlechtes Gewissen hat man schon, wenn in der TileList nachher 40 mal dieses Objekt angezeigt wird.

Die Entwickler von Flex haben aber soweit gedacht, dass nur die sichtbaren itemRenderer erstellt werden und diese auch wiederverwendet werden. Aber trotzdem wurde eine Schwerfälligkeit spürbar, und ein Fehler meinerseits auch.

Auf der Suche warum in meinen itemRenderern nach Scrollen falsche Bilder angezeigt wurden, fand ich die Lösung recht schnell (Wiederverwendung der gleichen itemRenderer und schlechte Komponentenprogrammierung) und auch den Hinweis das man bei itemRenderern mehr rausholen kann.

Anstatt die große schwere Canvas mitzuschleppen und alle ihre Vorzüge zu geniessen, erweitert man besser die UIComponent und implentiert IListItemRenderer wie Peter Ent es vormacht. Da sein Beispiel so gut ist, verzichte ich hier auf eigenen Code.

PZ Website v0.5

Es dauert länger als gedacht da ich im Moment nur wenig freie Zeit habe…

Fast fertig ist nun die Mediagalerie die Bilder, mp3s und Videos abspielen kann:
die Startseite Die Media Übersicht Eine Sounddatei abspielen

Wie der Titel sagt, ich glaube ich bin gut im Mittelfeld, da ich auch schon angefangen habe an der Perfomance zu schrauben, sollte das eine realistische Einschätzung sein.

 

PZ Website v0.2

Der 28.06 steht vor der Tür und ich will mein Versprechen halten das bis dahin “längst” die PZ Seite wieder online ist. Für den Moment gibts einen weiteren Screenshot der neuen Startseite. An Details feile ich noch, aber wie man erkennen kann ist die Anbindung zur Datenbank wieder da. Ich glaube aber die Schriftart muss noch gewechselt werden, aktuell ist sie nur sehr groß lesbar und dadurch verschenkt man viel Platz.

Adobe Flex: Schriftarten einbetten und Flex-CSS…

Thema Schriftarten einbetten: Das Problem kennt jeder Flashentwickler: Der tollste Effekt beeindruckt einfach nicht den dynamischen Text! In Flash musste man also die Schriftart einbetten und wenn man aus Versehen auch den kompletten asiatischen Zeichensatz mitnahm war die SWF Datei schnell mal ein paar MB groß.

In Flex ist das wesentlich einfacher geworden. Man bindet einfach per StyleSheet eine Schriftart ein und vergibt einen Familiennamen:

@font-face {
src: url('./fonts/arial.ttf');
fontFamily: "myArial";
}

Jetzt kann man über fontFamily=”myArial” auch alpharotation etc. auf Komponenten mit dieser Schriftart nutzen.

Das war auch der erste Flex-CSS Kontakt. Das obige Beispiel kann man einfach so in seinen MXML-Code kopieren und wenn der Ordner fonts existiert und darin eine Datei arial.ttf liegt funktioniert das direkt. Der <mx:Style/> Tag verfügt auch über eine source Eigenschaft in der man eine Flex-CSS Datei angeben kann und schon hat man seine Styles ausgelagert.


In der fonts.css steht das gleiche wie vorher im <mx:Style/> Tag, nur “src: url(../fonts/arial.ttf’);” weil ich die CSS Datei ja in einem Unterverzechnis liegen habe.

Flex legt nun im Debug und Release Ordner auch die Ordner css und fonts an und kopiert sogar die Dateien dort hinein. Der findige Flex-Entickler denkt nun er habe eine mächtige Möglichkeit gewonnen, mit der er das Aussehen der kompilierten Anwendung per externen Flex-CSS Dateien noch ändern kann. Aber: Die Idee zB einfach eine Schriftart auszutauschen oäfunktioniert nicht so einfach!

Es funktioniert etwas komplizierter. Im FlexBuilder hat man die Möglichkeit eine Flex-CSS Datei zu einer swf Datei zu komprimieren. Diese swf Datei kann man nun zur Laufzeit perStyleManager einladen. Angenommen man will zwei Styles entwerfen mit verschieden großen Schriftarten, erstellt man diese im FB, komprimiert sie jeweils zu einer swf Datei und nutzt folgende Codefragmente um zur Laufzeit den Style zu ändern:

initialize="StyleManager.loadStyleDeclarations('stylenormal.swf' )">
[...]
click="StyleManager.loadStyleDeclerations('stylebig.swf')"/>

Toll das man zur Laufzeit doch noch die Styles ändern kann, wenn man dies aber direkt über die Flex-CSS Dateien bewerkstelligen könnte, würde sich dieses Feature noch besser anfühlen.

Apropos besser anfühlen. Der Webentwickler hat mit CSS ein sehr mächtiges Werkzeug. Viele der W3-CSS Möglichkeiten bietet Flex-CSS allerdings nicht. Das man Styles überschreiben kann oder subgruppen bildet ala .news h1 {…} .news p {…} ist im XHTML Business Standard. Das bietet Flex-CSS leider nicht. Man kann auf oberster Ebene das Aussehen der Komponenten beeinflussen (Panel { … }), aber Subgruppen (Panel VBox {…} oder news VBox {…}) funktionieren nicht. Man muss also in Flex jeder Komponente einen styleName geben.

Abschließend sind mir noch zwei Sachen aufgefallen. Einerseits wunderte mich warum Eigenschaften wie rotation oder alpha nicht per Flex-CSS ansprechbar sind, anderseits sind alle Flex-CSS Eigenschaften unüberschaubar und nicht immer verständlich. Warum ist zB die Farbe der Hoverung eines Buttons als themeColor zu finden?
FlexBuilder bietet im Designmodus allerdings auch eine Komponente durchzustylen und dies dann als Flex-CSS zu exportieren – das ist eine gute Hilfe im unüberschaubaren Flex-CSS Universum.

PLayground Zero v0.0.0.0.x

Wie gesagt, ich veröffentliche hier ja immer den Status von der PZ Seite und da wollte ich schonmal einen ersten Screenshot bringen:

Das sieht natürlich nach weniger aus als es ist. Die meisten Komponenten habe ich einzelnd schon umgesetzt und ausprobiert ob meine Ideen funktionieren. Jetzt muss ich die nur noch zu einem Bündel schnüren und schick machen.

Ausserdem wollte ich noch nicht zuviel verraten – damit am Ende der große “Aha Effekt” auch wirklich groß ist. ;)

 

Adobe Flex: HowTo URLLoader [updated]

Auf der Suche wie man Dateien in Flex einlädt, findet man bei Adobe und anderen Seiten häufig folgendes Beispiel:

package {
import flash.display.Sprite;
import flash.events.*;
import flash.net.*;

public class URLLoaderExample extends Sprite {
public function URLLoaderExample() {
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, completeHandler);
var request:URLRequest = new URLRequest(“urlLoaderExample.txt”);
try {
loader.load(request);
} catch (error:Error) {
trace(“Unable to load requested document.”);
}
}

private function completeHandler(event:Event):void {
var loader:URLLoader = URLLoader(event.target);
trace(“completeHandler: ” + loader.data);
}
// alle weiteren Handler gelöscht
}
}// Quelle www.adobe.com

Dies lädt schnell dazu ein, den Code-Schnipsel in den <mx:Script> Tag seiner MXML Datei zu kopieren, per initialize-Event oder creationComplete-Event diese Funktion aufzurufen und man hat sein Datenmodell in der ViewComponente drin. Funktioniert, aber schön ist das nicht!

Ich hätte das beinah auch so gemacht, wenn ich mein Modell nicht in zwei Views brauchen würde, und wenn ich nicht 10 XML Dateien als Modell hätte. Nach langem Suchen wurde ich in meinem Kopf fündig: in der C & OOP Klausur habe ich einem Objekt per Parameter Funktionen übergeben. Also habe ich folgende Storage Klasse geschrieben:
Und da meine erste Version einer kleinen DOS-Attacke glich, habe ich jetzt eine Warteschlange eingebaut, sodass die XML Dateien nacheinander geladen werden und nicht alle gleichzeitig…

package
{
import flash.events.*;
import flash.net.*;

import mx.collections.XMLListCollection;

public class Storage {
[Bindable] public var homeData:XMLListCollection = null;
[Bindable] public var newsData:XMLListCollection = null;

// URLLoader für alle
private var loader:URLLoader = null;

// Lade-Warteschlange
private var queue:Object = new Object();

// singleton
private static var storage:Storage = null;
public static function getInstance():Storage {
if ( storage == null ) storage = new Storage();
return storage;
}

public function loadHomeData(url:String):void {
if ( homeData == null )	load(url, this.setHomeData);
}

public function setHomeData(event:Event):void {
homeData = new XMLListCollection(new XMLList(event.target.data));
// loader Variable null setzen
loader = null;
// naechste Datei laden
loadNext();
}

public function loadNewsData(url:String):void {
if ( newsData == null ) load(url, this.setNewsData);
}
public function setNewsData(event:Event):void {
newsData = new XMLListCollection(new XML(event.target.data).children());
loader = null;
loadNext();
}

private function load(url:String, handlerObject:Function):void
{
// ueberpruefen ob die URL schon in der Warteschlange ist
if ( queue[url] == undefined )  {
queue[url] = {url: url, handlerObject : handlerObject};
}
// Ueberpruefen ob grade ein Ladevorgang aktiv ist
if ( loader == null )  {
loader = new URLLoader();
//configure Listeners
loader.addEventListener(Event.COMPLETE, handlerObject);
// load File
var request:URLRequest = new URLRequest(url);
try {
loader.load(request);
} catch (error:Error) {

trace(“Unable to load ‘” + url + “‘”);
}
}
}

private function loadNext():void {
// ersten Index aus der Warteschlange holen
for ( var i:String in queue ) {
break;
}
// Ueberpruefen ob ein gueltiges Element vorleigt
if ( queue[i] != undefined ) {
// Ladevorgang anstossen
load(queue[i]['url'], queue[i]['handlerObject']);
}
}
}

Nun rufe ich in den Views im initialize-Event

initialize="{Storage.getInstance().loadNewsData('news.xml')}"

auf und nutze das public Object newsData als dataProvider. Damit das ganze übersichtlicher bleibt habe ich mich hier nur auf das Complete Event beschränkt.

Ich habe die load Funktion extra gewrappt, damit ich bei Änderungen in der Storage Klasse nicht alle Views durchwuseln muss.