In der Beispielanwendung „News Layout“ wird Text so formatiert, dass er einem Zeitungsartikel ähnelt. Der Eingabetext kann eine Schlagzeile, einen Untertitel und den Haupttext des Artikels enthalten. In Bezug auf die Breite und Höhe der Anzeige werden in der Beispielanwendung „News Layout“ die Schlagzeile und der Untertitel so formatiert, dass sie in voller Breite im Anzeigebereich dargestellt werden. Der Haupttext wird auf mindestens zwei Spalten aufgeteilt.
In diesem Beispiel werden die folgenden ActionScript-Programmiertechniken vermittelt:
-
Erweitern der TextField-Klasse
-
Laden und Anwenden einer externen CSS-Datei
-
Konvertieren von CSS-Stilen in TextFormat-Objekte
-
Abrufen von Daten zur Größe der Textanzeige mithilfe der TextLineMetrics-Klasse
Die Anwendungsdateien für dieses Beispiel finden Sie unter
www.adobe.com/go/learn_programmingAS3samples_flash_de
. Die Dateien der Anwendung „News Layout“ befinden sich im Ordner „Samples/NewsLayout“. Die Anwendung umfasst die folgenden Dateien:
Datei
|
Beschreibung
|
NewsLayout.mxml
oder
NewsLayout.fla
|
Die Benutzeroberfläche der Anwendung im Flex-Format (MXML) oder Flash-Format (FLA).
|
com/example/programmingas3/newslayout/StoryLayoutComponent.as
|
Eine UIComponent-Klasse von Flex, durch die die StoryLayout-Instanz eingefügt wird.
|
com/example/programmingas3/newslayout/StoryLayout.as
|
Die ActionScript-Hauptklasse, mit der alle Komponenten des Zeitungsartikels für die Anzeige angeordnet werden.
|
com/example/programmingas3/newslayout/FormattedTextField.as
|
Eine Unterklasse der TextField-Klasse, in der das zugehörige TextFormat-Objekt verwaltet wird.
|
com/example/programmingas3/newslayout/HeadlineTextField.as
|
Eine Unterklasse der FormattedTextField-Klasse, mit der die Schriftgröße so angepasst wird, dass der Text die gewünschte Breite hat.
|
com/example/programmingas3/newslayout/MultiColumnTextField.as
|
Eine ActionScript-Klasse, mit der Text auf mindestens zwei Spalten aufgeteilt wird.
|
story.css
|
Eine CSS-Datei, mit der Textformate für das Layout definiert werden.
|
Laden der externen CSS-Datei
Mit der Anwendung „News Layout“ wird zunächst der Text des Artikels aus einer lokalen XML-Datei geladen. Anschließend wird eine externe CSS-Datei mit Formatierungsdaten für die Schlagzeile, den Untertitel und den Haupttext geladen.
In der CSS-Datei sind drei Stile definiert, ein Standardabsatzformat für den Artikel sowie das h1-Format und das h2-Format für die Schlagzeile bzw. den Untertitel.
p {
font-family: Georgia, "Times New Roman", Times, _serif;
font-size: 12;
leading: 2;
text-align: justify;
indent: 24;
}
h1 {
font-family: Verdana, Arial, Helvetica, _sans;
font-size: 20;
font-weight: bold;
color: #000099;
text-align: left;
}
h2 {
font-family: Verdana, Arial, Helvetica, _sans;
font-size: 16;
font-weight: normal;
text-align: left;
}
Das zum Lesen der externen CSS-Datei verwendete Verfahren entspricht dem Verfahren, das im Abschnitt
Laden externer CSS-Dateien
beschrieben wird. Nach dem Laden der CSS-Datei wird in der Anwendung die
onCSSFileLoaded()
-Methode ausgeführt, wie im Folgenden dargestellt.
public function onCSSFileLoaded(event:Event):void
{
this.sheet = new StyleSheet();
this.sheet.parseCSS(loader.data);
h1Format = getTextStyle("h1", this.sheet);
if (h1Format == null)
{
h1Format = getDefaultHeadFormat();
}
h2Format = getTextStyle("h2", this.sheet);
if (h2Format == null)
{
h2Format = getDefaultHeadFormat();
h2Format.size = 16;
}
pFormat = getTextStyle("p", this.sheet);
if (pFormat == null)
{
pFormat = getDefaultTextFormat();
pFormat.size = 12;
}
displayText();
}
Mit der
onCSSFileLoaded()
-Methode wird ein StyleSheet-Objekt erstellt. Mit diesem Objekt werden dann die CSS-Eingabedaten analysiert. Der Haupttext des Artikels wird in einem MultiColumnTextField-Objekt angezeigt, in dem StyleSheet-Objekte direkt verwendet werden können. Für die Felder der Schlagzeile wird dagegen die HeadlineTextField-Klasse verwendet. Die entsprechende Formatierung erfolgt mithilfe eines TextFormat-Objekts.
Mit der
onCSSFileLoaded()
-Methode wird die
getTextStyle()
-Methode zweimal aufgerufen, um ein CSS-Stylesheet in ein TextFormat-Objekt zu konvertieren, das in jedem der beiden HeadlineTextField-Objekte verwendet wird.
public function getTextStyle(styleName:String, ss:StyleSheet):TextFormat
{
var format:TextFormat = null;
var style:Object = ss.getStyle(styleName);
if (style != null)
{
var colorStr:String = style.color;
if (colorStr != null && colorStr.indexOf("#") == 0)
{
style.color = colorStr.substr(1);
}
format = new TextFormat(style.fontFamily,
style.fontSize,
style.color,
(style.fontWeight == "bold"),
(style.fontStyle == "italic"),
(style.textDecoration == "underline"),
style.url,
style.target,
style.textAlign,
style.marginLeft,
style.marginRight,
style.indent,
style.leading);
if (style.hasOwnProperty("letterSpacing"))
{
format.letterSpacing = style.letterSpacing;
}
}
return format;
}
Die Eigenschaftsnamen und die Bedeutung der Eigenschaftswerte unterscheiden sich bei CSS-Stylesheets und bei TextFormat-Objekten. Mit der
getTextStyle()
-Methode werden die CSS-Eigenschaftswerte in die im TextFormat-Objekt erwarteten Werte umgewandelt.
Anordnen der Artikelelemente auf der Seite
Mit der StoryLayout-Klasse werden die Formatierung und das Layout der Felder für Schlagzeile, Untertitel und Haupttext im Zeitungsstil durchgeführt. Mit der
displayText()
-Methode werden die verschiedenen Felder zunächst erstellt und dann positioniert.
public function displayText():void
{
headlineTxt = new HeadlineTextField(h1Format);
headlineTxt.wordWrap = true;
headlineTxt.x = this.paddingLeft;
headlineTxt.y = this.paddingTop;
headlineTxt.width = this.preferredWidth;
this.addChild(headlineTxt);
headlineTxt.fitText(this.headline, 1, true);
subtitleTxt = new HeadlineTextField(h2Format);
subtitleTxt.wordWrap = true;
subtitleTxt.x = this.paddingLeft;
subtitleTxt.y = headlineTxt.y + headlineTxt.height;
subtitleTxt.width = this.preferredWidth;
this.addChild(subtitleTxt);
subtitleTxt.fitText(this.subtitle, 2, false);
storyTxt = new MultiColumnText(this.numColumns, 20,
this.preferredWidth, 400, true, this.pFormat);
storyTxt.x = this.paddingLeft;
storyTxt.y = subtitleTxt.y + subtitleTxt.height + 10;
this.addChild(storyTxt);
storyTxt.text = this.content;
...
Die einzelnen Felder werden jeweils unter dem vorherigen Feld platziert, indem für die
y
-Eigenschaft des jeweiligen Feldes der gleiche Wert wie für die
y
-Eigenschaft des vorherigen Feldes zuzüglich der Feldhöhe festgelegt wird. Diese dynamische Positionierungsberechnung ist erforderlich, da sich die Größe von HeadlineTextField-Objekten und MultiColumnTextField-Objekten entsprechend der Höhe des jeweiligen Inhalts ändern kann.
Ändern der Schriftgröße entsprechend der Feldgröße
Entsprechend der angegebenen Breite in Pixel und einer maximalen Anzahl anzuzeigender Zeilen wird die Schriftgröße im HeadlineTextField-Objekt so geändert, dass Text und Feld angepasst werden. Bei einem kurzen Text ist die Schrift groß, sodass eine Schlagzeile im Boulevardstil erstellt wird. Je länger der Text ist, umso kleiner ist die Schriftgröße.
Die Schriftgröße wird mit der
HeadlineTextField.fitText()
-Methode geändert, wie im Folgenden dargestellt:
public function fitText(msg:String, maxLines:uint = 1, toUpper:Boolean = false, targetWidth:Number = -1):uint
{
this.text = toUpper ? msg.toUpperCase() : msg;
if (targetWidth == -1)
{
targetWidth = this.width;
}
var pixelsPerChar:Number = targetWidth / msg.length;
var pointSize:Number = Math.min(MAX_POINT_SIZE, Math.round(pixelsPerChar * 1.8 * maxLines));
if (pointSize < 6)
{
// the point size is too small
return pointSize;
}
this.changeSize(pointSize);
if (this.numLines > maxLines)
{
return shrinkText(--pointSize, maxLines);
}
else
{
return growText(pointSize, maxLines);
}
}
public function growText(pointSize:Number, maxLines:uint = 1):Number
{
if (pointSize >= MAX_POINT_SIZE)
{
return pointSize;
}
this.changeSize(pointSize + 1);
if (this.numLines > maxLines)
{
// set it back to the last size
this.changeSize(pointSize);
return pointSize;
}
else
{
return growText(pointSize + 1, maxLines);
}
}
public function shrinkText(pointSize:Number, maxLines:uint=1):Number
{
if (pointSize <= MIN_POINT_SIZE)
{
return pointSize;
}
this.changeSize(pointSize);
if (this.numLines > maxLines)
{
return shrinkText(pointSize - 1, maxLines);
}
else
{
return pointSize;
}
}
In der
HeadlineTextField.fitText()
-Methode wird ein einfaches rekursives Verfahren zum Ändern der Schriftgröße verwendet. Zunächst wird die durchschnittliche Anzahl von Pixeln pro Zeichen im Text geschätzt und davon ausgehend eine anfängliche Punktgröße berechnet. Dann wird die Schriftgröße geändert und überprüft, ob im Text Zeilenumbrüche aufgetreten sind und eine die maximale Anzahl zulässiger Textzeilen übersteigende Anzahl von Zeilen entstanden ist. Wenn zu viele Zeilen vorhanden sind, wird die
shrinkText()
-Methode aufgerufen, um die Schriftgröße zu verringern. Anschließend wird der Vorgang wiederholt. Wenn die maximale Anzahl zulässiger Textzeilen nicht überschritten wurde, wird die
growText()
-Methode aufgerufen, um die Schriftgröße zu vergrößern. Dann wird der Vorgang wiederholt. Der Vorgang wird beendet, wenn durch Inkrementieren der Schriftgröße um einen weiteren Punkt zu viele Zeilen entstehen.
Aufteilen von Text auf mehrere Spalten
Mithilfe der MultiColumnTextField-Klasse wird Text auf mehrere TextField-Objekte aufgeteilt, die dann wie Zeitungsspalten angeordnet werden.
Mit dem
MultiColumnTextField()
-Konstruktor wird zunächst ein Array von TextField-Objekten erstellt, jeweils ein Objekt pro Zeile, wie im Folgenden dargestellt:
for (var i:int = 0; i < cols; i++)
{
var field:TextField = new TextField();
field.multiline = true;
field.autoSize = TextFieldAutoSize.NONE;
field.wordWrap = true;
field.width = this.colWidth;
field.setTextFormat(this.format);
this.fieldArray.push(field);
this.addChild(field);
}
Jedes TextField-Objekt wird mithilfe der
addChild()
-Methode zum Array und zur Anzeigeliste hinzugefügt.
Wenn sich die
text
-Eigenschaft oder die
styleSheet
-Eigenschaft des StoryLayout-Objekts ändert, wird die
layoutColumns()
-Methode aufgerufen, damit der Text neu angezeigt wird. Mit der
layoutColumns()
-Methode wird die
getOptimalHeight()
-Methode aufgerufen, um die entsprechende Pixelhöhe zu ermitteln, die zum Anpassen des Textes an die angegebene Layoutbreite erforderlich ist.
public function getOptimalHeight(str:String):int
{
if (field.text == "" || field.text == null)
{
return this.preferredHeight;
}
else
{
this.linesPerCol = Math.ceil(field.numLines / this.numColumns);
var metrics:TextLineMetrics = field.getLineMetrics(0);
this.lineHeight = metrics.height;
var prefHeight:int = linesPerCol * this.lineHeight;
return prefHeight + 4;
}
}
Zunächst wird mithilfe der
getOptimalHeight()
-Methode die Breite jeder Spalte berechnet. Anschließend werden die Breite und die
htmlText
-Eigenschaft des ersten TextField-Objekts im Array festgelegt. Mithilfe der
getOptimalHeight()
-Methode wird anhand des ersten TextField-Objekts die Gesamtanzahl der Zeilen mit Zeilenumbruch im Text festgestellt und dann die Anzahl der in jeder Spalte erforderlichen Zeilen ermittelt. Dann wird die
TextField.getLineMetrics()
-Methode aufgerufen, um ein TextLineMetrics-Objekt mit detaillierten Daten zur Größe des Textes in der ersten Zeile abzurufen. Mit der
TextLineMetrics.height
-Eigenschaft wird die volle Höhe einer Textzeile in Pixel angegeben, einschließlich Oberlänge, Unterlänge und Durchschuss. Die optimale Höhe des MultiColumnTextField-Objekts ergibt sich dann aus der Zeilenhöhe multipliziert mit der Anzahl der Zeilen pro Spalte, plus 4 für die Ränder eines TextField-Objekts von jeweils zwei Pixel oben und unten.
Es folgt der vollständige Code für die
layoutColumns()
-Methode:
public function layoutColumns():void
{
if (this._text == "" || this._text == null)
{
return;
}
var field:TextField = fieldArray[0] as TextField;
field.text = this._text;
field.setTextFormat(this.format);
this.preferredHeight = this.getOptimalHeight(field);
var remainder:String = this._text;
var fieldText:String = "";
var lastLineEndedPara:Boolean = true;
var indent:Number = this.format.indent as Number;
for (var i:int = 0; i < fieldArray.length; i++)
{
field = this.fieldArray[i] as TextField;
field.height = this.preferredHeight;
field.text = remainder;
field.setTextFormat(this.format);
var lineLen:int;
if (indent > 0 && !lastLineEndedPara && field.numLines > 0)
{
lineLen = field.getLineLength(0);
if (lineLen > 0)
{
field.setTextFormat(this.firstLineFormat, 0, lineLen);
}
}
field.x = i * (colWidth + gutter);
field.y = 0;
remainder = "";
fieldText = "";
var linesRemaining:int = field.numLines;
var linesVisible:int = Math.min(this.linesPerCol, linesRemaining);
for (var j:int = 0; j < linesRemaining; j++)
{
if (j < linesVisible)
{
fieldText += field.getLineText(j);
}
else
{
remainder +=field.getLineText(j);
}
}
field.text = fieldText;
field.setTextFormat(this.format);
if (indent > 0 && !lastLineEndedPara)
{
lineLen = field.getLineLength(0);
if (lineLen > 0)
{
field.setTextFormat(this.firstLineFormat, 0, lineLen);
}
}
var lastLine:String = field.getLineText(field.numLines - 1);
var lastCharCode:Number = lastLine.charCodeAt(lastLine.length - 1);
if (lastCharCode == 10 || lastCharCode == 13)
{
lastLineEndedPara = true;
}
else
{
lastLineEndedPara = false;
}
if ((this.format.align == TextFormatAlign.JUSTIFY) &&
(i < fieldArray.length - 1))
{
if (!lastLineEndedPara)
{
justifyLastLine(field, lastLine);
}
}
}
}
Nachdem die
preferredHeight
-Eigenschaft durch Aufrufen der
getOptimalHeight()
-Methode festgelegt wurde, werden die TextField-Objekte mithilfe der
layoutColumns()
-Methode durchlaufen und die Höhe jedes Textfelds jeweils auf den
preferredHeight
-Wert gesetzt. Anschließend wird mithilfe der
layoutColumns()
-Methode jedem Textfeld genau die Anzahl von Zeilen zugewiesen, bei der in keinem Textfeld ein Bildlauf durchgeführt werden muss und der Text in jedem Feld jeweils an der Stelle beginnt, an der der Text im vorherigen Feld endet. Wenn als Textausrichtungsstil „justify“ festgelegt wurde, wird anschließend die
justifyLastLine()
-Methode aufgerufen, um die abschließende Textzeile in einem Feld auszurichten. Andernfalls wird die letzte Zeile als Absatzende eingestuft und nicht ausgerichtet.
|
|
|