TextField Örneği: Gazete stili metin biçimlendirme

Flash Player 9 ve üstü, Adobe AIR 1.0 ve üstü

Haber Mizanpajı örneği, metni, basılı bir gazetedeki bir haber gibi görünecek şekilde formatlar. Girdi metni bir başlığı, alt başlığı ve öykünün gövdesini içerebilir. Bir görüntü genişliği ve yüksekliği verildiğinde, bu Haber Mizanpajı örneği, başlığı ve alt başlığı görüntüleme alanının tam genişliğini alacak şekilde formatlar. Öykü metni, iki veya daha fazla sütuna dağıtılır.

Bu örnek, aşağıdaki ActionScript programlama tekniklerini gösterir:

  • TextField sınıfını genişletme

  • Harici bir CSS dosyası yükleme ve uygulama

  • CSS stillerini TextFormat nesnelerine dönüştürme

  • Metin görüntüsü boyutu hakkında bilgi edinmek için TextLineMetrics sınıfını kullanma

Bu örneğin uygulama dosyalarını edinmek için bkz. www.adobe.com/go/learn_programmingAS3samples_flash_tr . Haber Mizanpajı uygulama dosyalarını Samples/NewsLayout klasörü içinde bulabilirsiniz. Uygulama aşağıdaki dosyaları içerir:

File

Açıklama

NewsLayout.mxml

veya

NewsLayout.fla

Flex (MXML) veya Flash (FLA) uygulaması için kullanıcı arabirimi.

com/example/programmingas3/newslayout/StoryLayoutComponent.as

StoryLayout örneğini yerleştiren bir Flex UIComponent sınıfı.

com/example/programmingas3/newslayout/StoryLayout.as

Görüntülenecek haberin tüm bileşenlerini düzenleyen ana ActionScript sınıfı.

com/example/programmingas3/newslayout/FormattedTextField.as

TextField sınıfının, kendi TextFormat nesnesini yöneten bir alt sınıfı.

com/example/programmingas3/newslayout/HeadlineTextField.as

FormattedTextField sınıfının, font boyutlarını istenen bir genişliğe sığacak şekilde ayarlayan bir alt sınırı.

com/example/programmingas3/newslayout/MultiColumnTextField.as

Metni iki veya daha fazla sütuna bölen bir ActionScript sınıfı.

story.css

Mizanpaj için metin stilleri tanımlayan bir CSS dosyası.

Harici CSS dosyasını okuma

Haber Mizanpajı uygulaması, yerel bir XML dosyasından öykü metni okuyarak başlar. Ardından, başlık, alt başlık ve ana metin için formatlama bilgilerini sağlayan harici bir CSS dosyasını okur.

CSS dosyası, öykü için standart bir paragraf stili ile başlık ve alt başlık için sırasıyla h1 ve h2 stilleri olmak üzere üç stil tanımlar.

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; 
}

Harici CSS dosyasını okumak için kullanılan teknik, Harici bir CSS dosyası yükleme konusunda açıklanan teknikle aynıdır. CSS dosyası yüklenince, uygulama aşağıda gösterilen onCSSFileLoaded() yöntemini çalıştırır.

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(); 
}

onCSSFileLoaded() yöntemi, bir StyleSheet nesnesi oluşturur ve bu nesnenin girdi CSS verilerini ayrıştırmasını sağlar. Öykünün ana metni, bir StyleSheet nesnesini doğrudan kullanabilen MultiColumnTextField nesnesinde görüntülenir. Ancak başlık alanları, formatlaması için bir TextFormat nesnesi kullanan HeadlineTextField sınıfını kullanır.

onCSSFileLoaded() yöntemi, bir CSS stil bildirimini her iki HeadlineTextField nesnesiyle kullanım için bir TextFormat nesnesine dönüştürmek üzere iki defa getTextStyle() yöntemini çağırır.

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; 
}

Özellik adları ve özellik değerlerinin anlamı, CSS stil bildirimleri ve TextFormat nesneleri arasında farklılık gösterir. getTextStyle() yöntemi, CSS özellik değerlerini TextFormat nesnesi tarafından beklenen değerlere çevirir.

Öykü öğelerini sayfada düzenleme

StoryLayout sınıfı, başlık, alt başlık ve ana metin alanlarını gazete stili düzenlemesi şeklinde formatlar ve düzenler. displayText() yöntemi, ilk olarak çeşitli alanlar oluşturur ve yerleştirir.

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; 
...

Her bir alan, y özelliğini önceki alanın y özelliği artı yüksekliğine eşit olacak şekilde ayarlayarak önceki alanın altına yerleştirilir. Bu dinamik yerleşim hesaplaması, HeadlineTextField nesneleri ve MultiColumnTextField nesneleri yüksekliğini içeriğinin sığacağı şekilde değiştirebildiği için gereklidir.

Font boyutunu alan boyutuna sığacak şekilde değiştirme

Piksel cinsinden bir genişlik ve görüntülenecek maksimum satır sayısı verildiğinde, HeadlineTextField metnin alana sığmasını sağlamak için font boyutunu değiştirir. Metin kısaysa, font boyutu tabloid stili bir başlık oluşturacak şekilde büyük olur. Metin uzunsa, font boyutu daha küçük olur.

Aşağıda gösterilen HeadlineTextField.fitText() yöntemi, font boyutlandırma işlemini yapar:

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; 
    } 
}

HeadlineTextField.fitText() yöntemi, fontu boyutlandırmak için basit bir yinelemeli teknik kullanır. lk olarak, metindeki her karakter için ortalama bir piksel sayısı tahmin eder ve buradan yola çıkarak başlangıç punto boyutunu hesaplar. Daha sonra font boyutunu değiştirir ve maksimum metin satırı sayısından daha fazlasını oluşturacak şekilde metinde sözcük kaydırma uygulanıp uygulanmadığını denetler. Çok fazla satır varsa, font boyutunu küçültmek ve yeniden denemek için shrinkText() yöntemini çağırır. Çok fazla satır yoksa, font boyutunu büyütmek ve yeniden denemek için growText() yöntemini çağırır. Font boyutunun bir punto daha büyütülmesinin çok sayıda satıra yol açacağı noktada işlem durdurulur.

Metni birden çok sütuna bölme

MultiColumnTextField sınıfı, daha sonra gazete sütunları gibi düzenlenen birden çok TextField nesnesine metni yayar.

MultiColumnTextField() yapıcısı ilk olarak, burada gösterildiği gibi her sütun için bir tane olacak şekilde TextField nesnelerinin bir dizisini oluşturur:

    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); 
    }

Her bir TextField nesnesi, addChild() yöntemiyle diziye ve görüntüleme listesine eklenir.

StoryLayout text özelliği veya styleSheet özelliği her değiştiğinde, metni yeniden görüntülemek için layoutColumns() yöntemini çağırır. layoutColumns() yöntemi, verilen mizanpaj genişliğine metnin tamamını sığdırmak için gereken doğru piksel yüksekliğini öğrenmek üzere getOptimalHeight() yöntemini çağırır.

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; 
    } 
}

İlk olarak getOptimalHeight() yöntemi, her sütunun genişliğini hesaplar. Ardından dizideki ilk TextField nesnesinin genişliğini ve htmlText özelliğini ayarlar. getOptimalHeight() yöntemi, metindeki sözcük kaydırması uygulanmış toplam satır sayısını bulmak için bu ilk TextField nesnesini kullanır ve bu noktadan yola çıkarak her sütunda kaç satır olması gerektiğini tanımlar. Daha sonra ilk satırdaki metnin boyutuyla ilgili ayrıntıları içeren bir TextLineMetrics nesnesini almak için TextField.getLineMetrics() yöntemini çağırır. TextLineMetrics.height özelliği, harflerin üst çıkıntısı, harflerin alt çıkıntısı ve satır aralığı da dahil olacak şekilde, bir metin satırının piksel cinsinden tam yüksekliğini temsil eder. MultiColumnTextField nesnesinin optimum yüksekliği; sütun başına satır sayısı ile satır yüksekliğinin çarpımına, bir TextField nesnesinin üstünde ve altında bulunan ikişer piksellik kenarlık için 4 değeri eklenerek elde edilir.

Tam layoutColumns() yönteminin kodu şu şekildedir:

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); 
        } 
    } 
    } 
}

getOptimalHeight() yöntemi çağrılarak preferredHeight özelliği ayarlandıktan sonra, layoutColumns() yöntemi TextField nesnelerini yineleyerek her birinin yüksekliğini preferredHeight değerine ayarlar. Daha sonra layoutColumns() yöntemi, tek bir alanda kaydırma gerçekleşmeyecek ve başka bir alanı izleyen alanlardaki metin, önceki alandaki metnin sona erdiği yerden başlayacak şekilde, her alana yeterli sayıda metin satırı dağıtır. Metin hizalama stili "yasla" olarak ayarlanmışsa, bir alandaki metnin son satırını yaslamak için justifyLastLine() yöntemi çağrılır. Aksi takdirde bu son satır, paragraf sonu satırı olarak değerlendirilir ve yaslanmazdı.