11 Replies Latest reply on May 29, 2012 1:25 PM by Flex harUI

    Custom Flex component has wrong width/height

    Stenrap2

      Hi,

       

      I'm working on a custom Flex component--a callout bubble with a Spark Label for text--and I'm having problems with its size. On screen, the component is 179 x 138 pixels. However, when I trace() the width/height of the component after it is created, I'm told it is 134 x 108. This is making it impossible to correctly position the callout based on its size!

       

      As you can see, I'm overriding updateDisplayList() and using the Graphics API to draw the callout bubble with a gradient:

       

      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
      {
          super.updateDisplayList(unscaledWidth, unscaledHeight);
          
          graphics.clear();
          
          label.move(15, 15);
          
          var matrix:Matrix = new Matrix();
          matrix.createGradientBox(unscaledWidth + 30, unscaledHeight + 30, Math.PI / 2, 0, unscaledHeight / 2);
          
          graphics.beginGradientFill(GradientType.LINEAR, [0x000000, 0x000000], [0.7, 0.7], [0, 255], matrix, SpreadMethod.PAD, InterpolationMethod.RGB);
          graphics.drawRoundRect(0, 0, unscaledWidth + 30, unscaledHeight + 30, 20, 20);
          
          var arrowWidth:Number  = 15;
          var arrowHeight:Number = 36;
          var arrowTop:Number    = (unscaledHeight + 30 - arrowHeight) / 2;
          
          graphics.moveTo(0, arrowTop);
          graphics.lineTo(-arrowWidth, arrowTop + arrowHeight / 2);
          graphics.lineTo(0, arrowTop + arrowHeight);
          graphics.endFill();
      }
      

       

       

      And, as you can see, when the text of the callout's label is changed, I'm invalidating properties and size:

       

      public function set text(value:String):void
      {
          _text = value;
          textChanged = true;
          label.text = text;
          label.addEventListener(FlexEvent.UPDATE_COMPLETE, labelReady);
      }
      
      private function labelReady(event:FlexEvent):void
      {
          label.removeEventListener(FlexEvent.UPDATE_COMPLETE, labelReady);
          invalidateProperties();
          invalidateSize();
       }
      
      override protected function commitProperties():void
      {
          super.commitProperties();
          
          if (textChanged)
          {
              textChanged = false;
              invalidateDisplayList();
          }
      }
      

       

      Any ideas what I'm doing wrong?

        • 1. Re: Custom Flex component has wrong width/height
          Stenrap2 Level 1

          I think I've discovered the problem (but no solution yet). It just occurred to me that the difference between what I see on screen (179 x 138) and what trace() is telling me (134 x 108) is precisely 45 x 30. Since I'm drawing the bubble exactly 45 x 30 pixels larger than the label, I did a trace() of only the label's width/height, and sure enough it is 134 x 108. So, for some odd reason, it seems Flex is not considering what I draw with the Graphics API when it calculates the width/height of the entire component. Is this a bug? If not, how can I coax Flex into giving me the width/height of the entire component?

          • 2. Re: Custom Flex component has wrong width/height
            leejk Level 1

            Similar problem here. I am setting the component's width/height in the measure() method, but the component's height/width properties are always 0 when they are traced. Is this a bug?

            • 3. Re: Custom Flex component has wrong width/height
              Flex harUI Adobe Employee

              It is not recommended to set width/height in measure().  See the documentation on custom components and how commitProperties/measure/updateDisplayList work.

              • 4. Re: Custom Flex component has wrong width/height
                leejk Level 1

                Really? Based on everything I've read so far, the measure() method is where the component's default width/height is defined.

                 

                I've determined that in order to read the component's width/height properties, I must do so after it's creationComplete event fires. Even though within the component itself, I can trace the component's measuredHeight & measuredWidth properties and they are valid immediatedly after the component is added to the DisplayList, the parent does not see them. Does that sound right?

                 

                My component won't ever change size actually, so should I be setting it's maxWidth & minWidth properties too?

                 

                thx

                • 5. Re: Custom Flex component has wrong width/height
                  Flex harUI Adobe Employee

                  Yes, really.

                   

                  Measure() should only provide measuredWidth/Height and measuredMinWidth/Height.  Later, in updateDisplayList(), each parent calls setActualSize or setLayoutBoundsSize on its children to give them their sizes (so they can apply sizes to their children).   Only then is the width/height valid.

                   

                  Setting width/height any sooner locks in the size of the component prevent resizing if needed to shrink or grow to fit in.  It can also cause the parent to have to stop and re-measure which will be a  drag on performance.

                   

                  You only need to set maxWidth/Height if the layout is going to try to stretch them.

                   

                  -Alex

                  • 6. Re: Custom Flex component has wrong width/height
                    leejk Level 1

                    Hi,

                     

                    Maybe I mist-stated what I was doing... here is one of my custom components. Does it look correct?

                     

                    thx

                     

                    package components

                    {

                              import flash.display.Shape;

                              import flash.geom.ColorTransform;

                              import flash.text.TextField;

                              import flash.text.TextFieldAutoSize;

                              import flash.text.TextFormat;

                              import flash.text.TextFormatAlign;

                     

                              import mx.core.UIComponent;

                     

                              import ui.LayoutConstants;

                     

                              public class Tab extends UIComponent

                              {

                                        private var _tabName:String;

                                        private var _tabNameChanged:Boolean;

                                        private var _labelTextfield:TextField;

                                        private var _bkgrndShape:Shape;

                                        private var _bkgrndColor:uint;

                                        private var _bkgrndColorChanged:Boolean;

                                        private var _tabType:String;

                                        private var _textFormat:TextFormat;

                     

                                        public function Tab()

                                        {

                                                  super();

                                                  _bkgrndColor = LayoutConstants.TAB_ACTIVE_COLOR;

                                        }

                     

                     

                                        override protected function createChildren():void

                                        {

                                                  super.createChildren();

                     

                                                  if (!_bkgrndShape)

                                                  {

                                                            _bkgrndShape = new Shape();

                                                            _bkgrndShape.graphics.lineStyle(1, _bkgrndColor);

                                                            _bkgrndShape.graphics.beginFill(_bkgrndColor);

                                                            _bkgrndShape.graphics.moveTo(0, 0);

                                                            _bkgrndShape.graphics.lineTo(0, -40);

                                                            _bkgrndShape.graphics.lineTo(2, -42);

                                                            _bkgrndShape.graphics.lineTo(4, -44);

                                                            _bkgrndShape.graphics.lineTo(LayoutConstants.TAB_WIDTH - 10, -44);

                                                            _bkgrndShape.graphics.lineTo(LayoutConstants.TAB_WIDTH, -34);

                                                            _bkgrndShape.graphics.lineTo(LayoutConstants.TAB_WIDTH, 0);

                                                            _bkgrndShape.graphics.lineTo(0, 0);

                                                            _bkgrndShape.graphics.endFill();

                                                            addChild(_bkgrndShape);

                                                  }

                     

                                                  if (!_labelTextfield)

                                                  {

                                                            _textFormat = new TextFormat();

                     

                                                            _textFormat.color = "0x000000";

                                                            _textFormat.font = LayoutConstants.UI_BOLD_FONT;

                                                            _textFormat.bold = true;

                                                            _textFormat.size = 12;

                                                            _textFormat.align = TextFormatAlign.CENTER;

                     

                                                            _labelTextfield = new TextField();

                                                            _labelTextfield.selectable = false;

                                                            _labelTextfield.mouseEnabled = false;

                                                            _labelTextfield.wordWrap = true;

                                                            addChild(_labelTextfield);

                                                            _labelTextfield.autoSize = TextFieldAutoSize.CENTER;

                                                  }

                                        }

                     

                                        override protected function commitProperties():void

                                        {

                                                  super.commitProperties();

                     

                                                  if (_tabNameChanged)

                                                  {

                                                            _labelTextfield.text = _tabName;

                                                            _labelTextfield.setTextFormat(_textFormat);

                                                            _tabNameChanged = false;

                                                  }

                     

                                                  if (_bkgrndColorChanged)

                                                  {

                                                            var colorTransform:ColorTransform = new ColorTransform();

                     

                                                            colorTransform.color = _bkgrndColor;

                                                            _bkgrndShape.transform.colorTransform = colorTransform;

                                                            _bkgrndColorChanged = false;

                                                  }

                                        }

                     

                                        override protected function measure():void

                                        {

                                                  super.measure();

                     

                                                  measuredWidth = _bkgrndShape.width;

                                                  measuredHeight = _bkgrndShape.height;

                                                  measuredMinHeight = _bkgrndShape.height;

                                                  measuredMinWidth = _bkgrndShape.width;

                                        }

                     

                                        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void

                                        {

                                                  super.updateDisplayList(unscaledWidth, unscaledHeight);

                     

                     

                                                  _labelTextfield.x = (unscaledWidth / 2) - (_labelTextfield.width / 2);

                                                  _labelTextfield.y = -(unscaledHeight / 2) - (_labelTextfield.height / 2);

                                        }

                     

                                        [Bindable]

                                        public function get tabName():String

                                        {

                                                  return _tabName;

                                        }

                     

                                        public function set tabName(value:String):void

                                        {

                                                  _tabName = value;

                                                  _tabNameChanged = true;

                                                  invalidateProperties();

                                                  invalidateDisplayList();

                                        }

                     

                     

                                        [Bindable]

                                        public function get tabType():String

                                        {

                                                  return _tabType;

                                        }

                     

                                        public function set tabType(value:String):void

                                        {

                                                  _tabType = value;

                                        }

                     

                                        public function set bkgrndColor(value:uint):void

                                        {

                                                  _bkgrndColor = value;

                                                  _bkgrndColorChanged = true;

                                                  invalidateProperties();

                                                  //invalidateDisplayList();

                                        }

                              }

                    }

                    • 7. Re: Custom Flex component has wrong width/height
                      Flex harUI Adobe Employee

                      Seems like your measure() method isn’t taking into account the textfield and the background shape?

                      • 8. Re: Custom Flex component has wrong width/height
                        leejk Level 1

                        Hmm... not sure I follow you. The textfield sits on top of the background image, so the measure() method just sets the size of the component to the size of the shape.

                        • 9. Re: Custom Flex component has wrong width/height
                          Flex harUI Adobe Employee

                          Maybe I don’t understand what you are looking for.  You are apparently not the original poster?

                           

                          I also noticed you seem to be drawing the background shape into negative coordinates.

                           

                          -Alex

                          • 10. Re: Custom Flex component has wrong width/height
                            leejk Level 1

                            Hi,

                             

                            I guess the question is, at what point after a custom componnent has been added to the display list using the addElement method can it's width & height properties be accessed and valid values be returned? Immediately querying the component's width and height does not work.

                             

                            thx

                            • 11. Re: Custom Flex component has wrong width/height
                              Flex harUI Adobe Employee

                              Unless the child has been given an explicit width and height by having those properties set directly, because parents size and position their children a child’s width/height is not known until the parent component has completed its updateDisplayList call.  There is no event for that, but an updateComplete event should follow shortly and can be forced by calling validateNow on the parent or one of its parents that have enough information to determine the width and height.