in GaiaXAndroid/src/main/kotlin/com/alibaba/gaiax/render/node/text/GXFitContentUtils.kt [51:238]
fun fitContent(
gxTemplateContext: GXTemplateContext,
gxNode: GXNode,
gxTemplateNode: GXTemplateNode,
gxStretchNode: GXStretchNode,
templateData: JSONObject
): Size<Dimension>? {
if (!gxTemplateNode.isTextType() && !gxTemplateNode.isRichTextType()) {
return null
}
if (!gxNode.isNodeVisibleInTree()) {
return null
}
val androidContext = gxTemplateContext.context
val nodeId = gxTemplateNode.getNodeId()
val nodeDataBinding = gxTemplateNode.dataBinding ?: return null
val finalCss = gxTemplateNode.css
val finalFlexBox = finalCss.flexBox
val finalStyle = finalCss.style
val nodeLayout = gxNode.layoutByBind ?: gxNode.layoutByPrepare
?: throw IllegalArgumentException("to fit content for text, but layout is null")
val gxCacheText = GXMeasureViewPool.obtain(androidContext)
gxCacheText.setTextStyle(finalCss)
val textContent = getMeasureContent(
gxTemplateContext, nodeId, gxCacheText, finalCss, gxTemplateNode, templateData
)
if (textContent == null) {
GXMeasureViewPool.release(gxCacheText)
return null
}
gxCacheText.text = textContent
val fontLines: Int? = finalStyle.fontLines
var result: Size<Dimension>? = null
var nodeWidth = nodeLayout.width
var nodeHeight = nodeLayout.height
// FIX: 如果databinding中引发了flex的改动,那么nodeLayout的结果可能不准确
val finalFlexBoxHeight = finalFlexBox.sizeForDimension?.height
if (gxNode.layoutByBind == null && finalFlexBoxHeight is Dimension.Points && nodeHeight != finalFlexBoxHeight.value) {
nodeHeight = finalFlexBoxHeight.value
}
if ((fontLines == null || fontLines == 1)) {
// 单行状态下,需要定高求宽
// 在某些机型上使用maxLine=1时,会导致中英混合、中英数字混合等一些文字无法显示
gxCacheText.setSingleLine(true)
// 计算宽高
gxCacheText.measure(0, 0)
var measuredWidth = gxCacheText.measuredWidth.toFloat()
val measuredHeight = gxCacheText.measuredHeight.toFloat()
val size = finalCss.flexBox.sizeForDimension
val isUndefineSize =
size?.width == null || size.width is Dimension.Auto || size.width is Dimension.Undefined
val minSize = finalCss.flexBox.minSizeForDimension
val isDefineMinSize =
minSize != null && (minSize.width !is Dimension.Auto || minSize.width !is Dimension.Undefined)
// fix: 如果没有定义宽度,但是定义了最小宽度,那么需要做一下修正
if (isUndefineSize && isDefineMinSize) {
// 如果测量的宽度,大于最小宽度,那么清除nodeWidth
if (measuredWidth >= nodeWidth) {
nodeWidth = 0F
}
// 如果测量的宽度,小于做小宽度,那么使用nodeWidth参与计算
else {
measuredWidth = nodeWidth
nodeWidth = 0F
}
}
var textHeight = nodeHeight
// FIXED: template_text_fitcontent_lines_null_width_fixed_height_null_padding_top_padding_bottom
val padding = finalFlexBox.paddingForDimension
val textTopAndBottomPadding =
(padding?.top?.value ?: 0F) + (padding?.bottom?.value ?: 0F)
// 高度等于上下padding之和,也认为是0高度
if (textHeight == textTopAndBottomPadding) {
textHeight = 0F
}
if (textHeight == 0F) {
// 兼容处理, 如果未设置高度,那么使用文本默认的高度
textHeight = measuredHeight
}
// FIXED: template_text_fitcontent_lines_null_width_null_height_fixed_padding_left_padding_right
val textLeftAndRightPadding =
(padding?.start?.value ?: 0F) + (padding?.end?.value ?: 0F)
result = when {
// 没有设置宽度
nodeWidth == 0F -> {
Size(Dimension.Points(measuredWidth), Dimension.Points(textHeight))
}
// 宽度等于左右padding之和,也认为是0宽度
nodeWidth == textLeftAndRightPadding -> {
Size(Dimension.Points(measuredWidth), Dimension.Points(textHeight))
}
measuredWidth >= nodeWidth -> {
Size(Dimension.Points(nodeWidth), Dimension.Points(textHeight))
}
else -> {
Size(Dimension.Points(measuredWidth), Dimension.Points(textHeight))
}
}
} else if (fontLines == 0) {
// 多行状态下,需要定宽求高
gxCacheText.setFontLines(fontLines)
if (nodeWidth == 0F) {
if (GXRegisterCenter.instance.extensionCompatibilityConfig?.isPreventFitContentThrowException == true) {
result = null
} else {
throw IllegalArgumentException("If lines = 0 or lines > 1, you must set text width")
}
} else if (nodeWidth > 0) {
// 计算宽高
gxCacheText.measure(0, 0)
val measuredWidth = gxCacheText.measuredWidth.toFloat()
// FIX: 和iOS端保持一致
// 如果计算结果行数一行,并且宽度小于最大宽度,那么使用实际的宽度作为结果
if (gxCacheText.lineCount == 1 && measuredWidth < nodeWidth) {
result = Size(
Dimension.Points(measuredWidth),
Dimension.Points(gxCacheText.measuredHeight.toFloat())
)
} else {
val widthSpec = View.MeasureSpec.makeMeasureSpec(
nodeWidth.toInt(), View.MeasureSpec.AT_MOST
)
gxCacheText.measure(widthSpec, 0)
result = Size(
Dimension.Points(nodeWidth),
Dimension.Points(gxCacheText.measuredHeight.toFloat())
)
}
}
} else if (fontLines > 1) {
// 多行状态下,需要定宽求高
gxCacheText.setFontLines(fontLines)
if (nodeWidth == 0F) {
if (GXRegisterCenter.instance.extensionCompatibilityConfig?.isPreventFitContentThrowException == true) {
result = null
} else {
throw IllegalArgumentException("If lines = 0 or lines > 1, you must set text width")
}
} else if (nodeWidth > 0) {
val widthSpec = View.MeasureSpec.makeMeasureSpec(
nodeWidth.toInt(), View.MeasureSpec.AT_MOST
)
gxCacheText.measure(widthSpec, 0)
result = Size(
Dimension.Points(gxCacheText.measuredWidth.toFloat()),
Dimension.Points(gxCacheText.measuredHeight.toFloat())
)
}
}
GXMeasureViewPool.release(gxCacheText)
return result
}