0

我需要基于 UIComponent 构建一个新的 UI 控件。控件的高度应该与宽度有一定的比例,并且还取决于显示的内容(内部文本的数量)。有人可以推荐我应该怎么做吗?

我试过用谷歌搜索,但似乎所有文章都试图避免谈论这个案子。我个人的感觉是,Flex 渲染的方式,即失效和更新显示列表,在处理这种情况时本身就效率低下。

以下是我的代码。一切正常,但似乎这不是最有效的方法,因为高度是在 updateDisplayList() 内部计算的,这会触发另一个 updateDisplayList()。

该控件在移动项目内部使用,因此当设备旋转时,父级的大小将发生变化,并且控件也需要调整大小。

所以,有几个问题:

  1. 在 measure() 中我应该做什么?由于高度基于实际宽度,因此在 updateDisplayList() 之前我无法获得最终宽度,因为控件的父级将宽度定义为百分比。
  2. 在 updateDisplayList() 的最开始计算高度是否正确?如果没有,我该怎么做?

下面是我的意思的一个例子。

import flash.text.TextField;
import flash.text.TextFieldAutoSize;

import mx.core.UIComponent;

public class MyControl extends UIComponent
{
public function MyControl()
{
    super();
}

public var textPadding:Number = 15;

public var heightRatio:Number = 1.61803398875;

private var _label:String;
private var labelChanged:Boolean = false;

public function get label():String
{
    return _label;
}

public function set label(value:String):void //can be long text with about 20-30 lines
{
    if (_label != value)
    {
        _label = value;
        labelChanged = true;

        invalidateProperties();
        invalidateSize();
        invalidateDisplayList();
    }
}

private var text:TextField;

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

    if (!text)
    {
        text = new TextField();
        text.autoSize = TextFieldAutoSize.LEFT;
        text.multiline = true;
        text.wordWrap = true;
        addChild(text);
    }
}

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

    if (labelChanged)
    {
        text.text = label;
        labelChanged = false;
    }
}

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

    //What should I do here?
}

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    text.width = unscaledWidth;

    if (text.height < unscaledWidth / heightRatio)
    {
        height = unscaledWidth / heightRatio + textPadding * 2;
    }
    else
    {
        height = text.height + textPadding * 2;
    }

    super.updateDisplayList(unscaledWidth, unscaledHeight);

    text.x = textPadding;
    text.y = textPadding;
}
}
4

3 回答 3

2

我需要基于 UIComponent 构建一个新的 UI 控件。控件的高度应该与宽度有一定的比例,并且还取决于显示的内容(内部文本的数量)。有人可以推荐我应该怎么做吗?

从技术上讲,你不能。

您对 Flex 工作原理的整个方法/理解存在根本缺陷。

Flex 组件永远不会自行调整大小。它始终由其父级确定大小。measure() 方法将设置理想值:measuredWidth、measuredHeight、measuredMinWidth 和measuredMinHeight。但是,它们只是提供给父容器的建议;可能会或可能不会使用它们。

MXML 掩盖了这个概念,您的误解很常见。

在大多数情况下,默认的 Flex 布局容器会尽最大努力尊重这些值,但它们有逻辑来处理空间不足的情况。例如; 一个有两个孩子的 VGroup 都设置为 100% 的高度不会将两个孩子的大小都设置为 VGroup 的 100%。

在没有看到使用和调整组件大小的代码的情况下,很难说出发生了什么。您设置的“高度”很可能不会被父容器覆盖;这是我相信这种方法有效的唯一原因。

我在这里做一些假设;但我认为你的测量方法应该是这样的:

override protected function measure():void
{
    super.measure();
    this.measuredwidth = text.getMeasuredOrExplicitWidth();
    this.measuredHeight = text.getMeasuredOrExplicitHeight()/heightRatio + textPadding * 2;
}

updateDisplayList(),应该是这样的:

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    text.width = unscaledWidth;
    text.height = unscaledWidth / heightRatio;

    super.updateDisplayList(unscaledWidth, unscaledHeight);

    text.x = textPadding;
    text.y = textPadding;
}

组件父容器中的 updateDisplayList() 应该执行如下操作:

myControlInstance.height = myControlInstance.measuredHeight;
myControlInstance.width = myControlInstance.measuredWidth;

Spark 框架使用所有相同的方法;但有时会稍微改变它们。所以,updateDisplayList() 和 measure() 通常在一个皮肤类中;或布局类。

于 2013-11-02T11:19:00.887 回答
0

根据 Adob​​e 文档http://livedocs.adobe.com/flex/3/html/help.html?content=ascomponents_advanced_2.html, measure() 用于测量默认大小, updateDisplayList() 用于大小和放置子组件。

要回答您的问题:

1)我会说什么都不做,因为你对默认大小不感兴趣。

2)我认为,这并不重要,因为值更改不会立即生效(当您编写 updateDisplayList 时将再次调用)。

我的建议是为 widthChanged 事件设置一个侦听器并使用它计算适当的高度。并在更改标签时进行高度计算。

于 2013-11-01T16:39:05.823 回答
0

没有办法绕过额外的更新周期,这只是带有文本重排的布局的本质。通常它是如何完成的(或者至少它是如何在 flex 组件中完成的)是首先根据它的首选宽度进行测量,如果测量没有明确边界的文本,这可能会非常宽。但是,此测量很重要,因为它会在 layoutBoundsWidth 或 layoutBoundsHeight 中设置上限之前通知父容器是否以及何时尝试尽可能扩大宽度。在第一次调用 updateDisplayList 中设置边界后,您应该调整文本大小和 invalidateSize(),以便可以在第二次通过时测量高度。抱歉,我没有代码示例,我在手机上。如果你需要它们,我可以在我在办公室的时候发布一些。

于 2013-11-02T01:36:14.740 回答