在树高度问题中显示HTML节点

时间:2009-02-08 10:17:32

标签: html flex

Grrr如此接近但仍然失败......

我在Flex中显示这个树,它包含两个节点类型:

  1. 常规节点,通常像文本一样呈现(因为它们是!)
  2. Rich(HTML)节点 - 这就是事情变得扭曲的地方
  3. 请注意,我的问题是当我动态添加新的(HTML)节点到我的树时。


    那么......我如何显示HTML节点?

    1. 我是TreeItemRenderer的子类
    2. 在该子类中,我覆盖了set data()并将一个文本子项添加到我的渲染器
    3. 因此我现在有:

      [icon] [label]

      [文本组件]

      为什么?

      默认标签是纯文本组件,不支持HTML,因此额外的组件:我想显示新人并忘记默认标签。

      1. (续)我重写updateDisplayList(),如果节点是一个丰富的节点,我将标签的高度设置为零,将我的组件的x和y设置为标签'x和y。
      2. 所以...我错过了什么?啊,是的:我需要设置节点的高度,因为HTML文本可以比文本更大或更小。

        1. (续)我重写measure()
        2. 如果我的节点不是富节点,我只需调用super.measure()并返回
        3. 如果 是一个丰富的,我给我的html组件一个宽度(htmlComponent.width = explicitWidth - super.label.x;),它的高度应该自动计算。
        4. 这给了我一个相当可靠的不可靠的结果!

          当我折叠/展开我的树时,每隔一段时间,我似乎得到了一个正确的HTML节点高度。另一次我得到'4'的高度恰好是HTML组件的填充,没有内容。

          我知道我必须在这里做一些相当愚蠢的事......但我不确定是什么。我会发布我的代码,如果我的漫无目的,无法理解......

          ****编辑:这是我的渲染器的源代码 如您所见,只有'notes'节点使用HTML。 我添加一个'htmlComponent'子项,它将显示富文本,而默认标签为零大小并消失。 它绝对是非常原始的代码,因为它正在进行中!

              package com.voilaweb.tfd
          {
              import mx.collections.*;
              import mx.controls.Text;
              import mx.controls.treeClasses.*;
              import mx.core.UITextField;
              import mx.core.UIComponent;
              import flash.text.TextLineMetrics;
          
              public class OutlinerRenderer extends TreeItemRenderer
              {
                  private function get is_note():Boolean
                  {
                      return ('outlinerNodeNote' == XML(super.data).name().localName);
                  }
          
                  override public function set data(value:Object):void
                  {
                      super.data = value;
                      var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
                      if(!htmlComponent)
                      {
                          htmlComponent = new Text();
                          htmlComponent.name = "htmlComponent";
                          addChild(htmlComponent);
                      }
                      if(is_note)
                          htmlComponent.htmlText = XML(super.data).attribute('nodeText');
                      else
                          htmlComponent.htmlText = null;
                      setStyle('verticalAlign', 'top');
                  }
          
           /*
            * Today we've learnt a valuable lesson: there is no guarantee of when createChildren() will be invoked.
            * Better be dirty and add children in set data()
                  override protected function createChildren():void
                  {
                      super.createChildren();
                      var htmlComponent:Text = new Text();
                      htmlComponent.name = "htmlComponent";
                      addChild(htmlComponent);
                  }
          */
                  override protected function measure():void
                  {
                    if(is_note)
                    {
                      super.measure();
                      var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
                      //Setting the width of the description field
                      //causes the height calculation to happen
                      htmlComponent.width = explicitWidth - super.label.x;
                      //We add the measuredHeight to the renderers measured height
                      //measuredHeight += (htmlComponent.measuredHeight - label.measuredHeight);
                      // Note the silly trick here...hopefully in the future I figure out how to avoid it
                      //
                      // Here is what happens: we check if measuredHeight is equal to decoration such as margin, insets...rather than that + some height
                      // If so, then we need to come up with an actual height which we do by adding textHeight to this height
          
                      // Note that I care about text being equal to margin etc but do not have proper access to these
                      // For instance UITextField.TEXT_HEIGHT_PADDING == 4 but is not accessible
                      // I am going to check if "<10" that will cover this case...
                      trace("For text " + htmlComponent.htmlText);
                      trace("width = " + htmlComponent.getExplicitOrMeasuredWidth()+" x height = " + htmlComponent.getExplicitOrMeasuredHeight());
                      var m:TextLineMetrics = htmlComponent.measureHTMLText(htmlComponent.htmlText);
                      //if(10 > htmlComponent.measuredHeight && !isNaN(htmlComponent.explicitHeight))
                      //htmlComponent.explicitHeight = m.height + htmlComponent.measuredHeight;
                      //if(htmlComponent.measuredHeight < 10) htmlComponent.explicitHeight = 50;
          
                      //measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - super.label.getExplicitOrMeasuredHeight());
                      measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - label.getExplicitOrMeasuredHeight());
                      trace("m:"+m.height+" Height: " + htmlComponent.getExplicitOrMeasuredHeight());
                    }
                    else
                    {
                      super.measure();
                    }
                  }     
          
                  override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
                  {
                      super.updateDisplayList(unscaledWidth, unscaledHeight);
                      label.height = label.getExplicitOrMeasuredHeight(); // If you tell me my height, then I shall use my variable height!
          
                      graphics.clear();
          
                      if(is_note)
                      {
                          label.height = 0;
                          var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
                          htmlComponent.x = label.x;
                          htmlComponent.y = label.y;
                          htmlComponent.height = htmlComponent.getExplicitOrMeasuredHeight();
          
                          graphics.beginFill(0x555555);
                          graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
                          graphics.endFill();
                      }
          
                      var complete:XMLList = XML(super.data).attribute('complete');
                      if(complete.length() > 0 && true == complete[0])
                      {
                          var startx:Number = data ? TreeListData(listData).indent : 0;
                          if(disclosureIcon)
                              startx += disclosureIcon.measuredWidth;
                          if(icon)
                              startx += icon.measuredWidth;
                          graphics.lineStyle(3, getStyle("color"));
                          var y:Number = label.y + label.getExplicitOrMeasuredHeight() / 2;
                          graphics.moveTo(startx, y);
                          graphics.lineTo(startx + label.getExplicitOrMeasuredWidth(), y);
                      }
                  }
              }
          }
          

3 个答案:

答案 0 :(得分:1)

您对默认渲染器中的标签组件做出了错误的假设 - 它能够显示html内容。这个渲染器适合我:

public class HtmlTreeItemRenderer extends TreeItemRenderer {
    override protected function commitProperties():void {
        super.commitProperties();
        label.htmlText = data ? listData.label : "";
        invalidateDisplayList();
    }
}

答案 1 :(得分:0)

如果您可以发布一些代码,肯定会有所帮助。

我想知道你为什么使用自定义html渲染器。是因为你想提到[icon] [label],你想在标签旁边显示一个图标?如果是这样,你可能最好使用iconField或iconFunction。

我想到的另一件事是variableRowHeight属性。如果您的节点具有不同的高度,则可能需要设置此值。

答案 2 :(得分:0)

试试吧。

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
           width="100%" height="100%" verticalScrollPolicy="off"
           horizontalScrollPolicy="off">

<mx:Script>
   <![CDATA[
      import mx.core.UITextField;

      private var texto:UITextField;

      override protected function createChildren():void
      {
         super.createChildren();

         texto = new UITextField();

         texto.setColor(0xFFFFFF);

         texto.multiline = true;
         texto.wordWrap = true;

         texto.autoSize = TextFieldAutoSize.LEFT;

         this.addChild(texto);

         //texto.text = data.title;
      }


      override public function set data(value:Object):void
      {
         super.data = value;
         if (value)
         {
          texto.htmlText = value.title;
          this.invalidateDisplayList();
         }
      }

      override protected function measure():void
      {
        super.measure();
      }

      override protected function updateDisplayList(unscaledWidth:Number,
                                       unscaledHeight:Number):void
      {
         super.updateDisplayList(unscaledWidth, unscaledHeight);

         if (texto)
          texto.width = this.width;
      }
   ]]>
</mx:Script>   

</mx:Canvas>