O exemplo Layout de notícias formata o texto para uma aparência similar a uma matéria de jornal impresso. O texto de entrada pode conter um título, um subtítulo e o corpo da matéria. Com determinada largura e altura de exibição, o exemplo de Layout de notícias formata o título e o subtítulo de modo a ocupar toda a extensão da área de exibição. O texto da matéria é distribuído em duas ou mais colunas.
Este exemplo ilustra as seguintes técnicas de programação do ActionScript:
-
Extensão da classe TextField
-
Carregamento e aplicação de um arquivo CSS externo
-
Conversão de estilos CSS em objetos TextFormat
-
Uso da classe TextLineMetrics para obter informações sobre o tamanho de exibição de texto
Para obter os arquivos de aplicativo desse exemplo, consulte
www.adobe.com/go/learn_programmingAS3samples_flash_br
. Os arquivos do aplicativo Layout de notícias podem ser encontrados na pasta Samples/NewsLayout. O aplicativo consiste nos seguintes arquivos:
Arquivo
|
Descrição
|
NewsLayout.mxml
ou
NewsLayout.fla
|
A interface do usuário do aplicativo para Flex (MXML) ou Flash (FLA).
|
com/example/programmingas3/newslayout/StoryLayoutComponent.as
|
Uma classe UIComponent do Flex que substitui a instância do StoryLayout.
|
com/example/programmingas3/newslayout/StoryLayout.as
|
A principal classe do ActionScript que organiza todos os componentes de uma matéria jornalística para exibição.
|
com/example/programmingas3/newslayout/FormattedTextField.as
|
Uma subclasse da classe TextField que gerencia seus próprio TextFormat.
|
com/example/programmingas3/newslayout/HeadlineTextField.as
|
Uma subclasse da classe FormattedTextField que ajusta os tamanhos das fontes de modo a se ajustarem à largura desejada.
|
com/example/programmingas3/newslayout/MultiColumnTextField.as
|
Uma classe ActionScript que divide texto em duas ou mais colunas.
|
story.css
|
Um arquivo CSS que define estilos de texto para o layout.
|
Leitura do arquivo CSS externo
O aplicativo Layout de notícias inicia pela leitura do texto da matéria de um arquivo XML local. Em seguida, ele lê um arquivo CSS externo que fornece as informações de formatação para o título, subtítulo e texto principal.
O arquivo CSS define três estilos, um estilo de parágrafo padrão para a matéria, e os estilos h1 e h2 para título e subtítulo respectivamente.
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;
}
A técnica usada par ler o arquivo CSS externo é a mesma descrita em
Carregamento de um arquivo CSS externo
Quando o arquivo CSS for carregado, o aplicativo executará o método
onCSSFileLoaded()
, como mostrado abaixo.
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();
}
O método
onCSSFileLoaded()
cria um objeto StyleSheet e o utiliza para analisar os dados das CSS de entrada. O principal texto da matéria é exibida em um objeto MultiColumnTextField, que pode usar um objeto StyleSheet diretamente. No entanto, os campos do título usam a classe HeadlineTextField, que usam um objeto TextFormat para formatação.
O método
onCSSFileLoaded()
chama o método
getTextStyle()
duas vezes para converter uma declaração de estilo CSS em um objeto TextFormat a ser utilizado com cada um dos dois objetos TextField do título.
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;
}
Os nomes das propriedades e o significado dos valores das propriedades são diferentes entre as declarações de estilo CSS e os objetos TextFormat. O método
getTextStyle()
converte os valores das propriedades das CSS nos valores esperados pelo objeto TextFormat.
Organização dos elementos da matéria na página
A classe StoryLayout formata e dispõe o título, o subtítulo e os campos de texto principais em uma organização com estilo de jornal. O método
displayText()
cria inicialmente e posiciona os diversos campos.
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;
...
Cada campo é posicionado abaixo do campo anterior definindo sua propriedade
y
de modo a igualar a propriedade
y
do campo anterior mais sua altura. Esse cálculo dinâmico de posicionamento é necessário porque os objetos HeadlineTextField e MultiColumnTextField podem alterar sua altura de modo a se adequarem ao conteúdo.
Alteração do tamanho da fonte para ajustar o tamanho do campo
Dada a largura em pixels e o número máximo de linhas, o HeadlineTextField altera o tamanho da fonte de modo a ajustar o texto ao campo. Se o texto for curto, o tamanho da fonte será grande, criando um título estilo tabloide. Se o texto for longo, o tamanho da fonte será menor.
O método
HeadlineTextField.fitText()
mostrado abaixo faz com que o dimensionamento de fonte funcione:
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;
}
}
O método
HeadlineTextField.fitText()
usa uma técnica recursiva simples para dimensionar a fonte. Em primeiro lugar, ele advinha um número médio de pixels por caractere no texto e, então, calcula um tamanho de ponto inicial. Em seguida, altera o tamanho da fonte e verifica se o texto tem quebra de palavras para criar mais do que o número máximo de linhas de texto. Se houver linhas em excesso, ele chamará o método
shrinkText()
para diminuir o tamanho da fonte e tentar novamente. Se não houver linhas em excesso, ele chamará o método
growText()
para aumentar o tamanho da fonte e tentar novamente. O processo parará no ponto em que incrementar o tamanho da fonte em mais um criará linhas em excesso.
Divisão de texto em várias colunas
A classe MultiColumnTextField expande o texto entre vários objetos TextField que são organizados, por sua vez, como colunas de jornal.
O construtor
MultiColumnTextField()
cria, primeiro, uma matriz de objetos TextFields, uma para cada coluna, conforme mostrado aqui:
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);
}
Cada objeto TextField é adicionado à matriz e à lista de exibição com o método
addChild()
.
Sempre que a propriedade
text
ou
styleSheet
do StoryLayout muda, ele chama o método
layoutColumns()
para re-exibir o texto. O método
layoutColumns()
chama o método
getOptimalHeight()
para calcular a altura em pixels correta necessária para ajustar todo o texto a determinada largura de layout.
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;
}
}
Em primeiro lugar, o método
getOptimalHeight()
calcula a largura de cada coluna. Em seguida, define a largura e a propriedade
htmlText
do primeiro objeto TextField na matriz. O método
getOptimalHeight()
usa esse primeiro objeto TextField para descobrir o número total de linhas com quebra de palavras no texto e, com base nesse número, identifica quantas linhas deve haver em cada coluna. Em seguida, ele chama o método
TextField.getLineMetrics()
para recuperar um objeto TextLineMetrics contendo detalhes sobre o tamanho do texto na primeira linha. A propriedade
TextLineMetrics.height
representa a altura completa de uma linha de texto, em pixels, incluindo ascendente, descendente e entrelinha. A altura ideal do objeto MultiColumnTextField é a altura da linha multiplicada pelo número de linhas por coluna, mais 4 para computar a borda de dois pixels em cima e embaixo de um objeto TextField.
Este é o código do método
layoutColumns()
completo:
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);
}
}
}
}
Depois da propriedade
preferredHeight
ter sido definida pela chamada do método
getOptimalHeight()
, o método
layoutColumns()
será iterado por meio dos objetos TextField definindo a altura de cada objeto para o valor
preferredHeight
. O método
layoutColumns()
distribui apenas linhas suficientes de texto para cada campo de modo que não ocorra rolamento em nenhum campo individual e o texto em cada campo sucessivo inicie onde termina o texto no campo anterior. Se o estilo de alinhamento de texto for definido como “justificar”, o método
justifyLastLine()
será chamado para justificar a linha final do texto em um campo. Caso contrário, a última linha será tratada como uma linha de fim de parágrafo e não justificada.
|
|
|