You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:如何将一个TextView的行高配置复制到另一个?

解决孟加拉语数字与阿拉伯数字TextView行高不一致导致的偏移问题

问题背景

应用本地化到孟加拉语时,发现孟加拉数字(如২)的行高显著大于阿拉伯数字(如2)。即便尝试统一行高和间距,阿拉伯数字TextView的每行占用空间更小,会出现累积偏移,需让两个TextView保持上下对称,且无法合并为一个组件。


解决方案

方案1:统一行高+文本垂直对齐+布局后动态设置

核心思路是关闭字体默认内边距,强制文本垂直居中,等待布局完成后获取孟加拉语TextView的准确行高,再同步给阿拉伯数字TextView:

修改MainActivity.kt:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }

        val firstTextView = findViewById<TextView>(R.id.firstText)
        val secondTextView = findViewById<TextView>(R.id.secondText)

        firstTextView.setText("২\n২\n২\n২\n২\n২\n২\n২")
        secondTextView.setText("2\n2\n2\n2\n2\n2\n2\n2")

        // 关闭字体默认上下内边距,消除额外空间差异
        firstTextView.includeFontPadding = false
        secondTextView.includeFontPadding = false

        // 设置文本垂直居中,确保每行内容对齐
        firstTextView.gravity = Gravity.CENTER_VERTICAL
        secondTextView.gravity = Gravity.CENTER_VERTICAL

        // 等待视图布局完成后,获取准确行高并统一设置
        firstTextView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                firstTextView.viewTreeObserver.removeOnGlobalLayoutListener(this)
                val fixedLineHeight = firstTextView.lineHeight
                TextViewCompat.setLineHeight(firstTextView, fixedLineHeight)
                TextViewCompat.setLineHeight(secondTextView, fixedLineHeight)
            }
        })
    }
}

方案2:布局约束强制高度匹配

在布局文件中添加双向高度约束,确保两个TextView总高度完全一致,进一步消除累积偏移:

修改activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="16dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/firstText"
        android:paddingEnd="4dp"
        android:textSize="24sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="@id/secondText"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/secondText"
        android:textSize="24sp"
        app:layout_constraintStart_toEndOf="@id/firstText"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="@id/firstText"/>

</androidx.constraintlayout.widget.ConstraintLayout>

方案3:自定义TextView强制固定行高(极端场景)

若上述方案仍有差异,可自定义TextView重写测量逻辑,彻底忽略字体自身的行高计算:

class FixedLineHeightTextView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = android.R.attr.textViewStyle
) : TextView(context, attrs, defStyleAttr) {

    var fixedLineHeight: Int = 0

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if (fixedLineHeight > 0) {
            val totalHeight = fixedLineHeight * lineCount + compoundPaddingTop + compoundPaddingBottom
            setMeasuredDimension(measuredWidth, totalHeight)
        }
    }

    override fun getLineHeight(): Int {
        return if (fixedLineHeight > 0) fixedLineHeight else super.getLineHeight()
    }
}

布局中替换为自定义TextView后,在代码中设置固定行高:

val firstTextView = findViewById<FixedLineHeightTextView>(R.id.firstText)
val secondTextView = findViewById<FixedLineHeightTextView>(R.id.secondText)

// ... 初始化文本后

firstTextView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
    override fun onGlobalLayout() {
        firstTextView.viewTreeObserver.removeOnGlobalLayoutListener(this)
        val fixedHeight = firstTextView.lineHeight
        firstTextView.fixedLineHeight = fixedHeight
        secondTextView.fixedLineHeight = fixedHeight
        firstTextView.requestLayout()
        secondTextView.requestLayout()
    }
})

内容的提问来源于stack exchange,提问作者BenjyTec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:06:03