fun fitContent()

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
    }