Flex multiline LabelItemRenderer for mobile chat

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Flex multiline LabelItemRenderer for mobile chat

chris_flex
Hi there,

searching for a solution to create a multiline LabelItemRenderer for a mobile chat
I found http://flexponential.com/2011/08/21/adding-multiline-text-support-to-labelitemrenderer/

My code is below. The problem is that after scolling the Height of the ItemRenderers do not fit anymore - it seems that they get the wrong heights of reused renderers. What am I doing wrong?

public class ChatMessageItemRenderer extends MultilineLabelItemRenderer
        {

                private static const CORNER_RADIUS:int = 10;
                private static const SIDE_OFFSET:int = 40;

                public function ChatMessageItemRenderer()
                {
                        super();
                        minHeight = 0;
                        percentWidth = 100;
                }

                private var dataChanged:Boolean;
                override public function set data(value:Object):void
                {
                        super.data = value;
                        dataChanged = true;
                        invalidateProperties();
                        invalidateDisplayList();
                }

                override protected function commitProperties():void
                {
                    super.commitProperties();
                        if(dataChanged)
                        {
                                labelDisplay.text = data.message;
                                dataChanged = false;
                        }
                }

                override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
                {
                    super.updateDisplayList(unscaledWidth, unscaledHeight);
                        setElementPosition(labelDisplay, data.isOwn ? 0 : SIDE_OFFSET, labelDisplay.getLayoutBoundsY());

                }

                // -------------------------------------------------

                override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
                {
                        var backgroundColor:int = data.isOwn ? 0xFF0000 : 0x00FF00;

                        graphics.beginFill(backgroundColor);
                        graphics.drawRoundRect(data.isOwn ? 0 : SIDE_OFFSET, 0, unscaledWidth - SIDE_OFFSET, unscaledHeight, CORNER_RADIUS, CORNER_RADIUS);
                        graphics.endFill();
                }


                ////////////////////////////////////////////////////////////////////////////
                //
                ////////////////////////////////////////////////////////////////////////////

                private var oldUnscaledWidth:Number;

                /**
                 * Upgrade layoutContents to handle text reflow.
                 */
                override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
                {
                        if(!labelDisplay)
                        {
                                return;
                        }

                        var paddingLeft:Number = getStyle("paddingLeft");
                        var paddingRight:Number = getStyle("paddingRight");
                        var paddingTop:Number = getStyle("paddingTop");
                        var paddingBottom:Number = getStyle("paddingBottom");
                        var verticalAlign:String = getStyle("verticalAlign");

                        var viewWidth:Number = unscaledWidth - paddingLeft - paddingRight;
                        var viewHeight:Number = unscaledHeight - paddingTop - paddingBottom;

                        var vAlign:Number;
                        if(verticalAlign == "top")
                        {
                                vAlign = 0;
                        }
                        else if(verticalAlign == "bottom")
                        {
                                vAlign = 1;
                        }
                        else // if (verticalAlign == "middle")
                        {
                                vAlign = 0.5;
                        }

                        if(label != "")
                        {
                                labelDisplay.commitStyles();
                        }

                        // Size the labelDisplay

                        // we want the labelWidth to be the viewWidth and then we'll calculate the height
                        // of the text from that
                        var labelWidth:Number = Math.max(viewWidth - SIDE_OFFSET, 0);

                        // keep track of the old label height
                        var oldPreferredLabelHeight:Number = 0;

                        // We get called with unscaledWidth = 0 a few times...
                        // rather than deal with this case normally,
                        // we can just special-case it later to do something smarter
                        if(labelWidth == 0)
                        {
                                // if unscaledWidth is 0, we want to make sure labelDisplay is invisible.
                                // we could set labelDisplay's width to 0, but that would cause an extra
                                // layout pass because of the text reflow logic.  To avoid that we can
                                // just set its height to 0 instead of setting the width.
                                setElementSize(labelDisplay, NaN, 0);
                        }
                        else
                        {
                                // grab old height before we resize the labelDisplay
                                oldPreferredLabelHeight = getElementPreferredHeight(labelDisplay);

                                // keep track of oldUnscaledWidth so we have a good guess as to the width
                                // of the labelDisplay on the next measure() pass
                                oldUnscaledWidth = unscaledWidth;

                                // set the width of labelDisplay to labelWidth.
                                // set the height to old label height.  If the height's actually wrong,
                                // we'll invalidateSize() and go through this layout pass again anyways
                                setElementSize(labelDisplay, labelWidth, oldPreferredLabelHeight);

                                // grab new labelDisplay height after the labelDisplay has taken its final width
                                var newPreferredLabelHeight:Number = getElementPreferredHeight(labelDisplay);

                                // if the resize caused the labelDisplay's height to change (because of
                                // text reflow), then we need to re-measure ourselves with our new width
                                if(oldPreferredLabelHeight != newPreferredLabelHeight)
                                {
                                        invalidateSize();
                                }
                        }

                        // Position the labelDisplay

                        var labelY:Number = Math.round(vAlign * (viewHeight - oldPreferredLabelHeight)) + paddingTop;
                        setElementPosition(labelDisplay, paddingLeft, labelY);
                }

                ////////////////////////////////////////////////////////////////////////////
                // HELPER METHODS
                ////////////////////////////////////////////////////////////////////////////

                override protected function createLabelDisplay():void
                {
                        super.createLabelDisplay();
                        labelDisplay.multiline = true;
                        labelDisplay.wordWrap = true;
                        labelDisplay.styleDeclaration = styleManager.getStyleDeclaration(".myStyle");
                        labelDisplay.setStyle("paddingTop", 10);
                        labelDisplay.setStyle("paddingLeft", 10);
                        labelDisplay.setStyle("paddingRight", 10);
                        labelDisplay.setStyle("paddingBottom", 10);
                }

        }

//

<?xml version="1.0"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" creationComplete="addDummyList()">

    <fx:Script>
       
<![CDATA[

        import mx.collections.ArrayCollection;

        private static var GAP:int = 5;

        private function addDummyList():void
        {
            var messages:ArrayCollection = new ArrayCollection();

            var ownMessage1:Object = {isOwn:true, message:"Das ist eine Nachricht ..."};
            var ownMessage2:Object = {isOwn:true, message:"Das ist eine Nachricht des eigenen Users - die 2."};
            var foreignMessage1:Object = {isOwn:false, message:"Das ist eine Nachricht des anderen Users - die 1. Das ist eine Nachricht des anderen Users - die 1. Das ist eine Nachricht des anderen Users - die 1."};
            var foreignMessage2:Object = {isOwn:false, message:"Das ist eine Nachricht des anderen Users - die 2."};

            messages = new ArrayCollection([ownMessage1, ownMessage2, foreignMessage1, foreignMessage2]);
            messageList.dataProvider = messages;
        }

        override protected function childrenCreated():void
        {
            super.childrenCreated();
            vlayout.gap = GAP;
            messageList.left = messageList.right = messageList.top = messageList.bottom = GAP;
        }

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
//            messageList.width = unscaledWidth;
//            messageList.height = unscaledHeight;
        }

        ]]>

    </fx:Script>


    <s:List id="messageList"
            itemRenderer="MyItemRenderer"
            horizontalScrollPolicy="off"
            useVirtualLayout="true">
        <s:layout>
            <s:VerticalLayout id="vlayout">
            </s:VerticalLayout>
        </s:layout>
    </s:List>

</s:Group>