Splitting text across multiple columns

The MultiColumnTextField class spreads text among multiple TextField objects which are then arranged like newspaper columns.

The MultiColumnTextField() constructor first creates an array of TextField objects, one for each column, as shown here:

    for (var i:int = 0; i < cols; i++)
    {
        var field:TextField = new TextField();
        field.autoSize = TextFieldAutoSize.NONE;
        field.wordWrap = true;
        field.styleSheet = this.styleSheet;
        
        this.fieldArray.push(field);
        this.addChild(field);
    }

Each TextField object is added to the array and added to the display list with the addChild() method.

Whenever the StoryLayout object's text property or styleSheet property changes, it calls the layoutColumns() method to redisplay the text. The layoutColumns() method calls the getOptimalHeight() method, shown below, to figure out the correct pixel height needed to fit all of the text within the given layout width.

public function getOptimalHeight(str:String):int
{
    if (fieldArray.length == 0 || str == "" || str == null)
    {
        return this.preferredHeight;
    }
    else
    {
        var colWidth:int = Math.floor( (this.preferredWidth - 
            ((this.numColumns - 1) * gutter)) / this.numColumns);

        var field:TextField = fieldArray[0] as TextField;
        field.width = colWidth;
        field.htmlText = str;

        var linesPerCol:int = Math.ceil(field.numLines / this.numColumns);
        var metrics:TextLineMetrics = field.getLineMetrics(0);
        var prefHeight:int = linesPerCol * metrics.height;
        return prefHeight + 4;
    }
}

First the getOptimalHeight() method calculates the width of each column. Then it sets the width and htmlText property of the first TextField object in the array. The getOptimalHeight() method uses that first TextField object to discover the total number of word-wrapped lines in the text, and from that it identifies how many lines should be in each column. Next it calls the TextField.getLineMetrics() method to retrieve a TextLineMetrics object that contains details about size of the text in the first line. The TextLineMetrics.height property represents the full height of a line of text, in pixels, including the ascent, descent, and leading. The optimal height for the MultiColumnTextField object is then the line height multiplied by the number of lines per column, plus 4 to account for the 2 pixel border at the top and the bottom of a TextField object.

Here is the code for the full layoutColumns() method:

public function layoutColumns():void
{
    if (this._text == "" || this._text == null)
    {
        return;
    }

    if (this.fitToText)
    {
        this.preferredHeight = this.getOptimalHeight(this._text);
    }
    
    var colWidth:int = Math.floor( (this.preferredWidth - 
        ((numColumns - 1) * gutter)) / numColumns);
    var field:TextField;
    var remainder:String = this._text;
    var fieldText:String = "";
    
    for (var i:int = 0; i < fieldArray.length; i++)
    {
        field = this.fieldArray[i] as TextField;
        field.width = colWidth;
        field.height = this.preferredHeight;
        
        field.x = i * (colWidth + gutter);
        field.y = 0;
        
        field.htmlText = "<p>" + remainder + "</p>";
        
        remainder = "";
        fieldText = "";
        
        var linesRemaining:int = field.numLines;
        var linesVisible:int = field.numLines - field.maxScrollV + 1;
        for (var j:int = 0; j < linesRemaining; j++)
        {
            if (j < linesVisible)
            {
                fieldText += field.getLineText(j);
            }
            else
            {
                remainder +=  field.getLineText(j);
            }
        }
        
        field.htmlText = "<p>" + fieldText + "</p>";
    }
}

After the preferredHeight property has been set by calling the getOptimalHeight() method, the layoutColumns() method iterates through the TextField objects, setting the height of each to the preferredHeight value. The layoutColumns() method then distributes just enough lines of text to each field so that no scrolling occurs in any individual field, and the text in each successive field begins where the text in the previous field ended.


Flash CS3