How to add a scrollbar to Text Layout Framework

Last month I wrote an article about using the Text Layout Framework in Flex 3.2 or AIR 1.5. The article was an introductory one, in which I explained the architecture and showed some basic code to use some of the main features of the framework. Some of you asked how one can add a scrollbar to scroll the text from a container that has more text than can be shown in the current viewport.

To tell you the truth, I was curious about how hard it would be, so today I just played a little bit and I managed to add a scrollbar to control the text.

You can test the code here.

scrollbar

Let me explain very quickly how I did it (if you want to see the details, click view source or scroll down this article for the code):

  1. I display the text using a single container; the size of this container is about 200 x 300 pixels.
  2. I added a mx:VScrollBar component to the page, setting the same height as the text container.
  3. When the TextFlow composes its text for displaying, a CompositionCompletionEvent.COMPOSITION_COMPLETE event is thrown. By listening for this event, I am able to determine if the text will actually flow outside of the text container.
  4. In the listener for CompositionCompletionEvent.COMPOSITION_COMPLETE, I get the total height of the composed text using _controller.calculateHeight() (this method returns the height in pixels. This is the height that the text needs in order to be shown entirely. If the height is bigger than the text container, then I set the max scroll value for the vertical scroll bar to that difference.
  5. I registered a listener for the scroll event on the vertical scroll bar. And next whenever the scroll bar moves, I use the current position of the scroll bar to set the DisplayObjectContainerController’s (this is the object that wraps the text container and it is used by TextFlow for displaying the text) verticalScrollPosition property (the value for this property is in pixels): _controller.verticalScrollPosition = event.position;
    This did half of the job: when the user moves the scroll bar, the text moves. Next, I had to synchronize the scroll bar when someone scrolls the text directly too.
  6. To do that, I registered another listener for the scroll event on the TextFlow it self. And whenever the users scrolls the text from the text container directly (for example by selecting a piece of text, holding the left mouse button, and moving it downward or upward), I use the current position of the DisplayObjectContainerController’s  verticalScrollPostion to set the scroll bar scrollPosition: scroll.scrollPosition = Math.ceil(_controller.verticalScrollPosition);
    You have to use ceil() on the value because the verticalScrollPosition returns a Number, not an Integer.
  7. And that’s it!
   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" viewSourceURL="srcview/index.html">
   3: <mx:Script>
   4:     <![CDATA[
   5:         import flashx.textLayout.events.ScrollEvent;
   6:         import mx.events.ScrollEvent;
   7:         import mx.events.MoveEvent;
   8:         import flashx.textLayout.container.IContainerController;
   9:         import flashx.textLayout.events.CompositionCompletionEvent;
  10:         import flashx.textLayout.edit.UndoManager;
  11:         import flashx.textLayout.edit.EditManager;
  12:         import flashx.textLayout.events.StatusChangeEvent;
  13:         import flashx.textLayout.elements.InlineGraphicElement;
  14:         import flashx.textLayout.container.DisplayObjectContainerController;
  15:         import flashx.textLayout.conversion.TextFilter;
  16:         import flashx.textLayout.elements.TextFlow;
  17:
  18:         [Embed(source="air.png")]
  19:         [Bindable]
  20:         static public var _imgClass:Class;
  21:
  22:         private var _textContainer:Sprite = null;
  23:
  24:         private static const _textInput:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008">
  25: <div>
  26:     <p>
  27:         <img source="./air.png"/>
  28:         <span>Flex is a highly productive, free open source framework for building and maintaining expressive web applications that deploy consistently on all major browsers, desktops, and operating systems. While Flex applications can be built using only the free Flex SDK, developers can use Adobe® Flex® Builder™ 3 software to dramatically accelerate development. Try Flex Builder 3 free for 60 days. Try ILOG Elixir to enhance data display in your Flex applications.</span>
  29:         <br/>
  30:     </p>
  31: </div>
  32: </TextFlow>;
  33:
  34:         private var _textFlow:TextFlow;
  35:         private var _controller:IContainerController;
  36:
  37:         private function init():void {
  38:             _textContainer = new Sprite();
  39:             canvas.rawChildren.addChild(_textContainer);
  40:             _controller = new DisplayObjectContainerController(_textContainer, canvas.width, canvas.height);
  41:
  42:             _textFlow = TextFilter.importToFlow(_textInput, TextFilter.TEXT_LAYOUT_FORMAT);
  43:             _textFlow.flowComposer.addController(_controller);
  44:             _textFlow.addEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGED, picLoaded);
  45:             _textFlow.addEventListener(CompositionCompletionEvent.COMPOSITION_COMPLETE, composeListener);
  46:             _textFlow.addEventListener(flashx.textLayout.events.ScrollEvent.SCROLL, scrollTextFlow);
  47:             //adding Select/Edit/Copy/Paste/Undo features
  48:             _textFlow.interactionManager = new EditManager(new UndoManager());
  49:             // initialize with a selection before the first character
  50:             _textFlow.interactionManager.setSelection(0,0);
  51:
  52:             _textFlow.flowComposer.updateAllContainers();
  53:         }
  54:
  55:         /**
  56:          * the composing of the text was finished;
  57:          * now I can see if I my text overflow the container
  58:          */
  59:         private function composeListener(event:CompositionCompletionEvent):void {
  60:             var textHeight:int = Math.ceil(_controller.calculateHeight());
  61:             if (textHeight < _controller.compositionHeight) {
  62:                 scroll.enabled = false;
  63:             } else {
  64:                 scroll.enabled = true;
  65:                 scroll.minScrollPosition = 0;
  66:                 scroll.maxScrollPosition = textHeight - _controller.compositionHeight;
  67:             }
  68:             _controller.verticalScrollPosition = 0;
  69:         }
  70:
  71:         /**
  72:          * listener for the picture load event; 
  73:          * it is time to update the flowComposer to display the picture
  74:          */
  75:         private function picLoaded(event:StatusChangeEvent):void {
  76:             var image:InlineGraphicElement = event.element as InlineGraphicElement;
  77:             _textFlow.flowComposer.updateAllContainers();
  78:         }
  79:
  80:         /**
  81:          * listener for the scroll event of the scrollbar
  82:          */
  83:         private function scrollListener(event:mx.events.ScrollEvent):void {
  84:             _textFlow.removeEventListener(flashx.textLayout.events.ScrollEvent.SCROLL, scrollTextFlow);
  85:             _controller.verticalScrollPosition = event.position;
  86:             _textFlow.addEventListener(flashx.textLayout.events.ScrollEvent.SCROLL, scrollTextFlow);
  87:         }
  88:
  89:         /**
  90:          * listener for the scroll event of the text flow container
  91:          */
  92:         private function scrollTextFlow(event:flashx.textLayout.events.ScrollEvent):void {
  93:             scroll.removeEventListener(mx.events.ScrollEvent.SCROLL, scrollListener);
  94:             scroll.scrollPosition = Math.ceil(_controller.verticalScrollPosition);
  95:             scroll.addEventListener(mx.events.ScrollEvent.SCROLL, scrollListener);
  96:         }
  97:     ]]>
  98: </mx:Script>
  99:
 100: <mx:HBox x="20" y="20">
 101:     <mx:Canvas id="canvas" width="200" height="300"  backgroundColor="#ffffff"/>
 102:     <mx:VScrollBar id="scroll" height="300" scroll="scrollListener(event)"/>
 103: </mx:HBox>
 104:
 105: </mx:Application>

I hope you enjoyed this!

25 thoughts on “How to add a scrollbar to Text Layout Framework

  1. Pingback: How to use Text Layout Framework in Flex 3.2 or AIR 1.5 : Mihai CORLAN

  2. Hi,
    Thanks for the post.

    If there is any wway to cancell the scrolling in text layout frame work.

    LIke if we have a text layout framework of 50*50 and the user is typing a lot data we have to restrict the user from typing

    Is it possible?

    Thanks,
    Ajai

  3. Hi Mihai,

    Setting the vertical scroll policy to off will stop the scrolling.

    But i need to prevent user enter data again once verticalscroll policy is set to off.
    Could you please post some sample if it ios possible for us to control it
    Thanks,
    Ajai

  4. Mihai,
    Your sample no longer works in the latest TLF/Gumbo releases.

    There is no such function controller.calculateHeight().

    Unfortunately, the contentHeight attribute is also not an exact height. Adobe forums indicate to use composePosition() prior to using contentHeight, but that doesnt seem to be totally accurate or reliable either.
    Tim

  5. @tim

    could be true, but I never said my sample is intended to work with Gumbo. I developed and tested only for Flex SDK 3.2

    thanks for the info!

  6. Hey Mihai,

    The code you wrote worked fantastic, thanks so much for the help!

    Justin

  7. Great use of controls! Thanks.
    I used the same code, but texts overwrites in Canvas area, in my case. Please make draggable/movable the images. Also make the texts draggable, as this happens in Flex TextArea control.
    Thanks & regards,
    Manoj

  8. Can you give example of how to add drag and drop functionality for text as well as inlinegraphicelement?

    thanx in advance

  9. Can u give some example of loading large text (using text layout framework) and splitting it , so that vertical scroll bar never come. i.e. suppose we have 20 lines text and only 4 lines are visible and when we click on next button
    then next 4 lines get visible.

  10. Hey Mihai,
    Can a similar functionality be implemented on a container (like a list) other than a textArea? Can a srollbar added separately be used to navigate the contents of another container?

    Thanks,
    Kunal

  11. @Kunal

    I don’t understand what do you mean by texArea. I didn’t use any textArea. I used a sprite to add the text inside of a canvas…

  12. Pingback: 在Flex中实现聊天表情图片支持-资料篇 | zrong's Blog

  13. Hi Mihai, First Thx for the great developer post. I used your idea as the starter for changes in our new version of ‘The Merlin Protocol’ website (themerlinprotocol.com) Its a site for a close friend that the author of a sci-fi book/series. Anyway, one thing I want to add but not sure it is possible… The old site (openlaszlo based) has a button at the end of the scroll area so that the visitor could hop to other sections of our site. There doesnt seem to be a straightforward way to put a inside of the TLF textflow area. Likewise I could put it outside but then our text would not be scrollable. Essentially I need a TLF:Button(s) all scrollable via a scrollbar. Have you ever seen an example of such a construct of mixing TLF with ‘std.’ flex components anywhere? TIA //GH

  14. Sorry some of the dummy HTML got removed from my post, which made it a little hard to follow…

    I mean a scroll area which has “TLF text (followed by) Flash standard buttons ALL scrollable via a standard scrollbar.

    Any pointers to TLF examples with a similar layout would be appreciated.

    (again) Cheers //GH

  15. @Greg Huddleston

    To tell you the truth I didn’t see anything like this. Maybe, you could have a look on the TLF forums. Because we open source TLF, it is possible to see the source code and extend it much easier.

  16. Hi Mihai, (thanks for the quick reply)

    I have been digging through the TLF forums for an answer, have not found anything (yet).

    If I do I will post a link back into answer to this into this group to help the next guy.

    Cheers //GH

  17. Is their an updated example for the final release of Text Layout Framework & Flex 4 as this does not work in the released version for the reasons mentioned above, but this post is one of the first that comes up when goggling this issue, and none of the other top hits seem to be anywhere even close.
    Thanks, ~ JT

  18. Hi thanks for the useful articles.how can i use this in Flash Builder 4.It has some error like :

    1046: Type was not found or was not a compile-time constant: CompositionCompletionEvent.

    or

    1046: Type was not found or was not a compile-time constant: ScrollEvent.

    thanks

  19. Pingback: 关于Adobe Flex图文混排的一些学习和资料 | 8only.cn-创见未来

Leave a Reply

Your email address will not be published. Required fields are marked *