多行文本视图与其基线对齐(ConstraintLayout Android Studio) [英] Multi-line text-views alignment to their baseline (ConstraintLayout Android Studio)

查看:96
本文介绍了多行文本视图与其基线对齐(ConstraintLayout Android Studio)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个TextViews "hi" "x" "Hello World" ,我想在它们的底部对齐Hello World文本(即hi_x_World).Hello World只是一行,但是 layout_width layout_height 都设置为 wrap_content .

它们具有不同的字体大小,因此即使我可以轻松地对齐文本视图框的底部,文本本身也不会对齐.

我发现了一个不同的XML参数 app:layout_constraintBaseline_toBaselineOf ="@ + id/text ,当我在TextView中只有一行时可以使用.但是,当我有2行或更多行时(例如Hello World TextView)所考虑的基准位于"Hello"而不是"World"中.

是否有任何方法可以更改设置以考虑世界"一词而不是你好"下方的基线?

解决方案

第二次更新:这是查看此

 < androidx.constraintlayout.widget.ConstraintLayoutandroid:id ="@@ id/layout"android:layout_width =" match_parent"android:layout_height =" match_parent"工具:context =.MainActivity".< TextViewandroid:id ="@@ id/hiddenView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text ="A";android:textSize ="50sp"android:visibility ="invisible"app:layout_constraintBottom_toBottomOf =" @ id/helloView"app:layout_constraintEnd_toEndOf ="parent"/>< TextViewandroid:id =" @ + id/hiView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text ="hi"android:textSize =" 46sp"app:layout_constraintBaseline_toBaselineOf =" @ id/hiddenView;app:layout_constraintEnd_toStartOf =" @ + id/xView"app:layout_constraintStart_toStartOf =" parent"app:layout_constraintTop_toTopOf =" @ id/helloView"/>< TextViewandroid:id ="@@ id/xView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text ="x"android:textSize =" 36sp"app:layout_constraintBaseline_toBaselineOf =" @ id/hiddenView;app:layout_constraintEnd_toStartOf =" @ + id/helloView"app:layout_constraintStart_toEndOf =" @ + id/hiView"app:layout_constraintTop_toTopOf =" @ id/helloView"/>< TextViewandroid:id =" @ + id/helloView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text =" Hello \ nWorld!"android:textSize ="50sp"app:layout_constraintBottom_toBottomOf =" parent"app:layout_constraintEnd_toEndOf ="parent"app:layout_constraintStart_toEndOf =" @ + id/xView"app:layout_constraintTop_toTopOf =" parent"/><按钮android:id ="@@ id/button"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:layout_marginTop =" 24dp"android:onClick ="onClick"android:text ="Adjust Base Lines"app:layout_constraintEnd_toEndOf ="parent"app:layout_constraintStart_toStartOf =" parent"app:layout_constraintTop_toBottomOf =" @ + id/helloView"/></androidx.constraintlayout.widget.ConstraintLayout> 



第一个答案:如另一个答案中所述,仅使用 ConstraintLayout 约束是无法做到这一点的.您将需要采用程序化解决方案.

在每个 TextView 中是一个

单击按钮时,将计算基线位置,并将填充添加到"hi"图标的顶部.和"x"表示 TextViews .

具体细节将随实现方式而变化,但这是通用技术.

MainActivity.kt

  class MainActivity:AppCompatActivity(){重写fun onCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}fun onClick(view:View){button.isEnabled =否//从TextView获取StaticLayout瓦尔布局= helloView.layout//获取Hello World的最后一行的基线位置!TextView,"hi"和"x"表示val helloBaseLIne = layout.getLineBaseline(layout.lineCount-1)val hiBaseLine = hiView.layout.getLineBaseline(0)val xBaseLine = xView.layout.getLineBaseline(0)//移位"hi";和"x"表示降低,使基线与您好世界的基线匹配!hiView.updatePadding(top = helloBaseLIne-hiBaseLine)xView.updatePadding(top = helloBaseLIne-xBaseLine)}} 

activity_main.xml

 < androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width =" match_parent"android:id ="@@ id/layout"android:layout_height =" match_parent"工具:context =.MainActivity".< TextViewandroid:id ="@@ id/hiView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text ="hi"android:textSize =" 46sp"app:layout_constraintTop_toTopOf =" @ id/helloView"app:layout_constraintEnd_toStartOf =" @ + id/xView"app:layout_constraintStart_toStartOf =" parent"/>< TextViewandroid:id ="@@ id/xView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text ="x"android:textSize =" 36sp"app:layout_constraintTop_toTopOf =" @ id/helloView"app:layout_constraintEnd_toStartOf =" @ + id/helloView"app:layout_constraintStart_toEndOf =" @ + id/hiView"/>< TextViewandroid:id =" @ + id/helloView"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:text =" Hello \ nWorld!"android:textSize ="50sp"app:layout_constraintBottom_toBottomOf =" parent"app:layout_constraintEnd_toEndOf ="parent"app:layout_constraintStart_toEndOf =" @ + id/xView"app:layout_constraintTop_toTopOf =" parent"/><按钮android:id ="@@ id/button"android:layout_width =" wrap_content"android:layout_height =" wrap_content"android:layout_marginTop =" 24dp"android:text ="Adjust Base Lines"android:onClick =" onClickapp:layout_constraintEnd_toEndOf ="parent"app:layout_constraintStart_toStartOf =" parent"app:layout_constraintTop_toBottomOf =" @ + id/helloView"/></androidx.constraintlayout.widget.ConstraintLayout> 

I have three TextViews "hi", "x" and "Hello World" which I would like to align in the bottom of the Hello World text (ie hi_x_World). Hello World is just one line but both layout_width and layout_height are set to wrap_content.

They have different font sizes so even though I can easily align the bottom of the boxes of the textviews, the text itself does not become aligned.

I found a different XML parameter app:layout_constraintBaseline_toBaselineOf="@+id/text that works when I only have one line in the TextView. However, when I have 2 or more lines (like in the Hello World TextView) the baseline that's considered is in the 'Hello' instead of 'World'.

Is there any way to change the setting to consider the baseline below the word "World" instead of "Hello" ?

解决方案

Second update: This is another way of looking at the first solution taken from this Stack Overflow answer that will also work with ConstraintLayout. This solution uses a custom TextView. The custom TextView returns the baseline of the last line of text in the TextView from the getBaseline() function instead of the baseline of the first line which is the default action. This is a nice, clean solution (IMO) that takes into account multi-line TextViews but also gravity, etc.

Kotlin version of BaselineLastLineTextView

class BaselineLastLineTextView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {

    override fun getBaseline(): Int {
        val layout = layout ?: return super.getBaseline()
        val baselineOffset = super.getBaseline() - layout.getLineBaseline(0)
        return baselineOffset + layout.getLineBaseline(layout.lineCount - 1)
    }
}


First update: This is an update to my answer below which is still a valid solution (IMO). This is an alternate approach that does not involve any Java/Kotlin code and can be accomplished just using XML.

Create an invisible wrap_content TextView that has the same font size as the "Hello World!" TextView. (You may also need to consider padding and margins depending upon the actual layout.) Constrain this new view to the bottom of "Hello World!", make it invisible and set the contents to something short that is guaranteed to occupy just one line. This will give you a target view that has the same base line as the last line of the "Hello World!" view.

Constrain the base lines of "hi" and "x" to the new invisible view. All views will now share the same base line and without coding.

<androidx.constraintlayout.widget.ConstraintLayout 
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/hiddenView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A"
        android:textSize="50sp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@id/helloView"
        app:layout_constraintEnd_toEndOf="parent" />

    <TextView
        android:id="@+id/hiView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hi"
        android:textSize="46sp"
        app:layout_constraintBaseline_toBaselineOf="@id/hiddenView"
        app:layout_constraintEnd_toStartOf="@+id/xView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/helloView" />

    <TextView
        android:id="@+id/xView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="x"
        android:textSize="36sp"
        app:layout_constraintBaseline_toBaselineOf="@id/hiddenView"
        app:layout_constraintEnd_toStartOf="@+id/helloView"
        app:layout_constraintStart_toEndOf="@+id/hiView"
        app:layout_constraintTop_toTopOf="@id/helloView" />

    <TextView
        android:id="@+id/helloView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello\nWorld!"
        android:textSize="50sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/xView"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:onClick="onClick"
        android:text="Adjust Base Lines"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/helloView" />


</androidx.constraintlayout.widget.ConstraintLayout>



First answer: As noted in another answer, there is no way to do this just using ConstraintLayout constraints. You will need to resort to a programmatic solution.

Within each TextView is a StaticLayout that can reveal a bit about the typography of the text. By referring to the static layout, padding can be added to the appropriate views to make the base lines align.

In this demo, the three TextViews simply have their tops aligned. Initially, the views look like this:

When the button is clicked, the base line locations are calculated and padding is added to the tops of the "hi" and "x" TextViews.

Details will vary with the implementation, but this is the general technique.

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun onClick(view: View) {
        button.isEnabled = false
        // Get the StaticLayout from the TextView
        val layout = helloView.layout

        // Get the base line location for last line of Hello World! TextView, "hi" and "x"
        val helloBaseLIne = layout.getLineBaseline(layout.lineCount - 1)
        val hiBaseLine = hiView.layout.getLineBaseline(0)
        val xBaseLine = xView.layout.getLineBaseline(0)
        
        // Shift "hi" and "x" down so base lines match that of hello world!
        hiView.updatePadding(top = helloBaseLIne - hiBaseLine)
        xView.updatePadding(top = helloBaseLIne - xBaseLine)
    }
}

activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:id="@+id/layout"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/hiView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hi"
        android:textSize="46sp"
        app:layout_constraintTop_toTopOf="@id/helloView"
        app:layout_constraintEnd_toStartOf="@+id/xView"
        app:layout_constraintStart_toStartOf="parent"/>

    <TextView
        android:id="@+id/xView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="x"
        android:textSize="36sp"
        app:layout_constraintTop_toTopOf="@id/helloView"
        app:layout_constraintEnd_toStartOf="@+id/helloView"
        app:layout_constraintStart_toEndOf="@+id/hiView" />

    <TextView
        android:id="@+id/helloView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello\nWorld!"
        android:textSize="50sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/xView"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="Adjust Base Lines"
        android:onClick="onClick"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/helloView" />


</androidx.constraintlayout.widget.ConstraintLayout>

这篇关于多行文本视图与其基线对齐(ConstraintLayout Android Studio)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆