Text Layout Frameworkによるブックビューア制作の流れ(1)

by key

前回のエントリで書いたBCCKSのブックビューアの制作の流れについて説明します。

まず、今回の目標は以下のようなものです。

  • 今までHTML+CSSで作っていたビューアをFlashに移植する
  • ユーザが作った既存のブックも大体同じように表示される
  • HTML+CSSではできない、Flashならではの表現を探る

TextField/TextFormatを使った今までの方法では、後方互換性や進んだ表現を行うのは難しいと考えたので、Flash Text Engine(FTE) 及びその上に構築されている Text Layout Framework(TLF) に初挑戦することにしました。

記事中のコードは全てFlex SDK 4.0.0.8155でビルドしています。それ以前のSDKだと、TLFのAPI構成と挙動が大きく違いますのでご注意ください。

Flash Text Engineを触ってみる

どういったものなのかあまり調べず、試しにFlash Text Engineを使ってみました。以下は複数行テキストを表示するだけのコードです。

  1. // 表示するテキスト
  2. var text:String = "Hello, Flash Text Engine";
  3. // フォーマット
  4. var elementFormat:ElementFormat = new ElementFormat(null, 24);
  5. // テキストエレメント(テキストとフォーマット情報を持つContentElement)
  6. var textElement:TextElement = new TextElement(text, elementFormat);
  7. // テキストブロック(指定したContentElementからTextLineを作るファクトリ)
  8. var block:TextBlock = new TextBlock(textElement);
  9.  
  10. var prevLine:TextLine;
  11. for (;;) {
  12.     var textLine:TextLine = block.createTextLine(prevLine, 120);
  13.     if (textLine) {
  14.         textLine.y = prevLine ? prevLine.y + textLine.height : textLine.ascent;
  15.         addChild(textLine);
  16.         prevLine = textLine;
  17.     } else {
  18.         break;
  19.     }
  20. }

前半部分を見ると、文字列/フォーマット情報/フォーマットされたテキスト/テキスト表示 のそれぞれのステージを扱うクラスが用意されていて嬉しいです。

一方で、後半を見ると、テキストを表示する際には行ごとにTextLineを作らなくてはならず、そのレイアウトやテキスト選択のサポートも自前で行う必要があるようです。

つまり、FTEはテキストの表示に対する最も低レベルの操作を提供するものであり、日常的な用途でそのまま使うにはかなり扱いにくいようです。

Text Layout Frameworkを触ってみる

TLFはFTEの上位に構築されたフレームワークです。選択・編集がサポートされており、マークアップ形式(後述)のテキストを扱うことができます。

以下は選択可能な複数行テキストを表示するコードです。

  1. // 表示するテキスト
  2. var text:String = "Hello, Text Layout Framework";
  3. // TextFlowはフォーマットされた一続きのテキスト
  4. var textFlow:TextFlow = TextFilter.importToFlow(text, TextFilter.PLAIN_TEXT_FORMAT);
  5. // TextFlowの属性を設定してフォーマットを行う
  6. textFlow.fontSize = 24;
  7. // TextFlowのユーザインタラクションを行うクラス
  8. textFlow.interactionManager = new SelectionManager();
  9. // ContainerControllerはTextFlowとコンテナ(TextLineが格納されるSprite)を繋ぐ
  10. var controller:ContainerController = new ContainerController(this, 250, 50);
  11. // FlowComposerは一つまたは複数のContainerControllerを管理する
  12. textFlow.flowComposer.addController(controller);
  13. textFlow.flowComposer.updateAllControllers();

TextFieldとはかなり使い勝手が異なっています。

特にaddChildが無いので、今までのFlash/AS3に慣れていると気持ち悪い感じがするかもしれませんが、前述のFTEのコードを思い出してみましょう。

FTEではTextLineの作成と管理を自前で行う必要がありました。おそらくその役目をContainerControllerクラスが担っているのでしょう。

(いま確かめてみたら、やはりContainerControllerのコンストラクタに渡したSpriteにTextLineがaddChildされていました)

ContainerControllerを複数作ってみる

ContainerControllerが複数のTextLineの管理を行うことが想像できたので、今度は複数のContainerControllerを割り当ててみました。

  1. var text:String = "Hello, Text Layout Framework";
  2. text = [text, text, text, text, text, text, text].join(" ");
  3.  
  4. var textFlow:TextFlow = TextFilter.importToFlow(text, TextFilter.PLAIN_TEXT_FORMAT);
  5. textFlow.interactionManager = new EditManager();
  6.  
  7. var container1:Sprite = new Sprite();
  8. var container2:Sprite = new Sprite();
  9. textFlow.flowComposer.addController(new ContainerController(container1, 100, 100));
  10. textFlow.flowComposer.addController(new ContainerController(container2, 100, 100));
  11. textFlow.flowComposer.updateAllControllers();
  12.  
  13. container2.y = 150;
  14. addChild(container1);
  15. addChild(container2);

恐らく、複数のContainerControllerの管理を行うのがIFlowComposerなのだと思います。

TextFlow.flowComposerには最初からStandardFlowComposerインスタンスが入っています。ということは将来的にStandardじゃないFlowComposerのお世話になるかもしれませんね。

実行してみると、離れたコンテナ同士でテキスト選択の連携がとれています。labsのサンプルではこの機能のことをLinked Containersと呼んでいたので僕もそう呼んでいます。

さりげなくinteractionManagerをEditManagerにしておいたので、テキスト編集もこのまま行えます。こんなに複雑なことがAS3で書かれていて驚きですね。

長くなってきたので、ここらへんで。

次回はXMLマークアップとBCCKSでの実際の作業について書きます。

タグ: ,

コメントをどうぞ