egret-docs-master/extension/EUI/autoLayout/layoutPrinciple/README.md

3.1 KiB
Raw Permalink Blame History

自动布局本质上就是封装了各种更加便捷的相对布局属性,结合失效验证机制,在合适的触发条件下(如尺寸发生改变时),自动设置相关对象的xywidthheight等属性。所以无论过程是怎么样的,最终结果都是直接体现在x,y,width,height这些最原始的属性上并没有脱离显示对象原始的API。

在上一节内容中,简单介绍了跟布局有关的两个方法:measure()updateDisplayList()。本节详细说明这个两个方法:

updateDisplayList()方法负责布局子项(即设置子项的x,y,width,height),或做一些矢量重绘操作。measure()自动测量出当前适合子项的相关属性(width,height等)。

举个例子:有一个容器(Group),里面放一个单行文本(Label),想要文本始终在容器中水平居中(horizotalCenter = 0)。不需要显式设置文本的width,这时measure()会在文本内容改变时,自动测量出当前合适的width,父级就会根据这个width,重新布局它的x,y

EUI 里所有的组件都是这样:如果不显式设置宽高,就调用measure()方法测量出一个最佳尺寸,在没有被父级强制布局情况下,这个值最终赋值给widthheight属性。反之,如果显式设置了组件的widthheight属性,widthheight就使用显式设置的值。若组件同时被设置了widthheightmeasure()方法将不会被调用。至于何为测量的”最佳尺寸”不同的组件有各自的测量方式容器是能刚好放下所有子项的尺寸文本是能完整显式文本内容的尺寸而Image则是内部要显示的位图素材的尺寸。还有其他的组件具体在各自的measure()方法里实现。多个组件都需要测量的时候,会按照显式列表深度,从内向外测量。而布局阶段正好相反,从外向内。具体细节参考失效验证机制的内容。

总之,如果希望自定义的组件像框架里的标准组件一样,能加入自动布局体系,就必须要同时重写measure()updateDisplayList()方法。

Group是容器基类。它不负责具体的布局规则,而是做了一个解耦处理。增加layout属性,类型为LayoutBaseGroup中的measure()updateDisplayList()方法的内容为:

protected measure():void {
    if (!this.$layout) {
        this.setMeasuredSize(0, 0);
        return;
    }
    this.$layout.measure();
}

protected updateDisplayList(unscaledWidth:number, unscaledHeight:number):void {
    if (this.$layout) {
        this.$layout.updateDisplayList(unscaledWidth, unscaledHeight);
    }
    this.updateScrollRect();
}

Group把自己的measure()方法交给layout.measure()实现,updateDisplayList()交给layout.updateDisplayList()实现。也就是把具体的布局方式解耦出来,形成独立的LayoutBase类。这样所有的容器都可以采用Group+LayoutBase的组合的方式,来设置任意的布局。