简体   繁体   English

在Flex中,构建高度基于宽度和内容的UI组件的更好方法是什么?

[英]In Flex, what is a better way to build UI component whose height is based on width and content?

I need to build a new UI control based on UIComponent. 我需要构建一个基于UIComponent的新UI控件。 The control's height should have a certain ratio to the width and also depends on what content is shown (amount of text inside). 控件的高度应与宽度具有一定的比例,并且还取决于显示的内容(内部文本的数量)。 Could anybody recommend how I should do this? 有人可以推荐我该怎么做吗?

I have tried googling around, but it seems all articles just try to avoid talking about the case. 我试过谷歌搜索,但似乎所有文章只是试图避免谈论案件。 My personal feeling is that the way Flex renders, ie invalidate and update display list, is natively inefficient to deal with the situation. 我个人的感觉是,Flex渲染的方式,即无效和更新显示列表,本身就无法有效地处理这种情况。

Below are my codes. 以下是我的代码。 It works all fine, but it seems this is not the most efficient way because the height is calculated inside updateDisplayList(), which triggers another updateDisplayList(). 它工作得很好,但似乎这不是最有效的方法,因为高度是在updateDisplayList()内部计算的,它会触发另一个updateDisplayList()。

The control is used inside a mobile project, so when the device is rotated, the parent's size will be changed and the control needs to be resized as well. 控件在移动项目中使用,因此当旋转设备时,将更改父级的大小,并且还需要调整控件的大小。

So, a few questions: 那么,有几个问题:

  1. What should I do in measure()? 我应该怎么做measure()? Since the height is based on actual width, I cannot get the final width until updateDisplayList(), because the parent of the control has width defined as percentage. 由于高度基于实际宽度,因此我无法在updateDisplayList()之前获得最终宽度,因为控件的父级宽度定义为百分比。
  2. Is it correct to calculate the height at the very beginning of updateDisplayList()? 在updateDisplayList()的最开始计算高度是否正确? If not, how should I do it? 如果没有,我该怎么办?

Below is an example what I mean. 以下是我的意思的一个例子。

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;
}
}

I need to build a new UI control based on UIComponent. 我需要构建一个基于UIComponent的新UI控件。 The control's height should have a certain ratio to the width and also depends on what content is shown (amount of text inside). 控件的高度应与宽度具有一定的比例,并且还取决于显示的内容(内部文本的数量)。 Could anybody recommend how I should do this? 有人可以推荐我该怎么做吗?

Technically you can't. 从技术上讲,你做不到。

Your whole approach / understanding of how Flex works is fundamentally flawed. 您对Flex工作原理的整体方法/理解存在根本缺陷。

A Flex component will never size itself. Flex组件永远不会自行调整大小。 It is always sized by its parent. 它始终由其父级调整大小。 The measure() method will set ideal values: measuredWidth, measuredHeight, measuredMinWidth, and measuredMinHeight. measure()方法将设置理想值:measuredWidth,measuredHeight,measuredMinWidth和measuredMinHeight。 But, they are just suggestions to be provided to the parent container; 但是,它们只是提供给父容器的建议; which may or may not use them. 可能会也可能不会使用它们。

MXML masks this concept and your misunderstanding is very common. MXML掩盖了这个概念,你的误解很常见。

In most cases, the default Flex layout containers will do their best to honor these values, but they have logic to handle situations where their is not enough space. 在大多数情况下,默认的Flex布局容器将尽力遵守这些值,但它们具有处理空间不足的情况的逻辑。 For example; 例如; a VGroup with two children that are both set to 100% height won't size both children to 100% of the VGroup. 具有两个子项的VGroup都设置为100%高度不会将两个子项的大小设置为VGroup的100%。

Without seeing your code that uses and sizes your component it is tough to say what is going on. 如果没有看到使用和调整组件大小的代码,就很难说出发生了什么。 Most likely the 'height' that you are setting is not getting overwritten by the parent container; 很可能你设置的“高度”不会被父容器覆盖; and that is the only reason I can believe this approach works. 这是我相信这种方法有效的唯一原因。

I'm making some assumptions here; 我在这里做一些假设; but I think your measure method should look something like this: 但我认为你的测量方法应该是这样的:

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

updateDisplayList(), should be something like this: 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;
}

The updateDisplayList() in the component's parent container should do something like this: 组件的父容器中的updateDisplayList()应该执行以下操作:

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

The Spark framework uses all the same methods; Spark框架使用所有相同的方法; but sometimes shuffles them around a bit. 但有时候会把它们拖了一下。 So, the updateDisplayList() and measure() are usually in a skin class; 因此,updateDisplayList()和measure()通常在皮肤类中; or a layout class. 或布局类。

According to Adobe Documentation http://livedocs.adobe.com/flex/3/html/help.html?content=ascomponents_advanced_2.html , measure() is used to measure default size and updateDisplayList() is used to size and place child components. 根据Adobe文档http://livedocs.adobe.com/flex/3/html/help.html?content=ascomponents_advanced_2.html,measure ()用于测量默认大小,updateDisplayList()用于调整和放置子项组件。

To answer your questions: 回答你的问题:

1) I'd say to do nothing, since you're not interested in default size. 1)我会说什么也不做,因为你对默认大小不感兴趣。

2) I think, it doesn't matter since the value change doesn't have immediate effect (as you write updateDisplayList will be called again). 2)我认为,这并不重要,因为值更改不会立即生效(因为您将再次调用updateDisplayList)。

My suggestion is to have an listener for widthChanged event and use it calculate proper height. 我的建议是有一个widthChanged事件的监听器,并使用它计算适当的高度。 And to do height calculation when label is changed. 并在更改标签时进行高度计算。

There is no way around the extra update cycle, that is just the nature of layout with text reflow. 没有办法绕过额外的更新周期,这只是具有文本重排的布局的本质。 Usually how it's done (or at least how it's done in the flex components) is to measure based on it's preferred width first, which may be quite wide if measuring text with no explicit bounds. 通常它是如何完成的(或者至少它是如何在flex组件中完成的)是首先根据它的首选宽度进行测量,如果测量没有明确边界的文本,这可能相当宽。 This measurement is important however as it notifies parent containers if and when it should try and expand out the width as much as possible, before the uper limit is set in layoutBoundsWidth or layoutBoundsHeight. 但是,此测量非常重要,因为它会在layoutBoundsWidth或layoutBoundsHeight中设置uper limit之前,如果及何时尝试扩展宽度,则通知父容器。 Once your bounds are set in the first call to updateDisplayList, you should resize your text and invalidateSize() so you can measure the height on the second pass. 一旦在第一次调用updateDisplayList中设置了边界,就应该调整文本大小并使invalidSize()无效,这样就可以测量第二遍的高度。 Sorry I have no code examples, im on the mobile. 对不起我手机上没有代码示例。 If you need them, I can post some when I'm in the office. 如果你需要它们,我可以在办公室时张贴一些。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM