packages/core/src/rendering/render-flex.ts (61 lines of code) (raw):
import { assert } from '@canvas-ui/assert'
import { RenderObject } from './render-object'
import { RenderView, ViewParentData } from './render-view'
import { StyleMap } from './style-map'
import { StyleToYoga } from './yoga'
export class FlexParentData<ChildType extends RenderObject = RenderObject> extends ViewParentData<ChildType> {
}
export class RenderFlex<ChildType extends RenderObject<FlexParentData<ChildType>> = RenderObject> extends RenderView<ChildType> {
protected override setupParentData(child: RenderObject) {
if (!(child.parentData instanceof FlexParentData)) {
child.parentData = new FlexParentData()
}
}
override get alwaysHoldYogaNode() {
// RenderFlex 总是持有 yogaNode
return true
}
protected override setupYogaNode() {
super.setupYogaNode()
// 同步容器样式
this.handleFlexDirectionChange(this.style.flexDirection)
this.handleFlexWrapChange(this.style.flexWrap)
this.handleJustifyContentChange(this.style.justifyContent)
this.handleAlignItemsChange(this.style.alignItems)
this.handleAlignContent(this.style.alignContent)
// 追踪变更
this.style.on('flexDirection', this.handleFlexDirectionChange, this)
this.style.on('flexWrap', this.handleFlexWrapChange, this)
this.style.on('justifyContent', this.handleJustifyContentChange, this)
this.style.on('alignItems', this.handleAlignItemsChange, this)
this.style.on('alignContent', this.handleAlignContent, this)
}
private handleFlexDirectionChange(value: StyleMap['flexDirection'] = 'row') {
assert(this.yogaNode)
this.yogaNode.setFlexDirection(StyleToYoga.flexDirection[value])
}
private handleFlexWrapChange(value: StyleMap['flexWrap'] = 'nowrap') {
assert(this.yogaNode)
this.yogaNode.setFlexWrap(StyleToYoga.flexWrap[value])
}
private handleJustifyContentChange(value: StyleMap['justifyContent'] = 'flex-start') {
assert(this.yogaNode)
this.yogaNode.setJustifyContent(StyleToYoga.justifyContent[value])
}
private handleAlignItemsChange(value: StyleMap['alignItems'] = 'stretch') {
assert(this.yogaNode)
this.yogaNode.setAlignItems(StyleToYoga.alignItems[value])
}
private handleAlignContent(value: StyleMap['alignContent'] = 'flex-start') {
assert(this.yogaNode)
this.yogaNode.setAlignContent(StyleToYoga.alignContent[value])
}
override performLayout() {
assert(this.yogaNode, `${this.id}: RenderFlex 的 yogaNode 不能是 undefined`)
// 从根 yogaNode 开始布局
if (!(this.parent instanceof RenderFlex)) {
this.yogaNode.calculateLayout(
// todo(haocong) 设法读取 parentSize,以支持根节点的百分比宽高
)
}
// 更新自己的 Size 和 Offset
this.updateOffsetAndSize()
// 更新子节点的 Size 和 Offset
this.visitChildren(child => {
child.layoutAsChild(true, true)
})
}
}