简体   繁体   中英

Constrain TextView in two views at the same time

I have to build a layout like this:

我正在尝试构建这样的布局

There are two TextView , the blue and the black one.

String inside "black" TextView should be placed after "blue" TextView and if the text is too long jump down like if it was constrained also to the right of the image. I can't use SpannableString and stuff because the "blue" TextView may be an ImageView in some cases.

I'm trying to use ConstraintLayout which I think is the most completed layout we have, but I can not figure it out.

I will appreciate if someone can show some component, approach or workaround to solve this. Thanks!

----- EDITED ---- Another example:

在此处输入图片说明

The easiest solution would be to use a span to place the black text within the TextView of the blue text. If the black text is within an ImageView then constrain the black text ImageView to the leftmost ImageView . When you have black text which is not in an ImageView , make the ImageView's visibility equal to "gone".

But let's assume that you have two TextViews with text that cannot be combined.

Case 1 - Two TextViews

In addition to the leftmost ImageView , there are two TextViews . One holds blue text and one holds black text. The goal is to make these two TextViews appear like they are part of a single TextView such that the black text immediately follows the blue text.

To do this, position the black TextView to completely overlay the blue TextView . This can be easily accomplished with a ConstraintLayout .

activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/dandelion_flower" />

    <TextView
        android:id="@+id/textBlue"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="Blue text that spane more than one line of its TextView."
        android:textColor="@android:color/holo_blue_bright"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="@id/imageView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="@+id/imageView" />

    <TextView
        android:id="@+id/textBlack"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="This is some black text"
        android:textColor="@android:color/black"
        app:layout_constrainedWidth="true"
        app:layout_constraintBottom_toBottomOf="@+id/imageView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="@+id/imageView" />

</androidx.constraintlayout.widget.ConstraintLayout>

Without adjustment, the black text will just appear on top of the blue text. The goal now is to pad out the blue text TextView will enough space so that it moves to the end of the blue text. We can do this by adjusting the black text with newline characters (to move it down) and space characters (to move it over). One place to do this is in the onCreate() function. (See comments in the following code.)

// Wait for the layout to complete before getting measurements.
findViewById<TextView>(R.id.textBlue).doOnNextLayout {
    val blueText = it as TextView
    val blackText = findViewById<TextView>(R.id.textBlack)
    // The TextViews have been laid out. Determine how many lines are used for the blue text.
    val blueLayout = blueText.layout
    val blueLineCount = blueText.layout.lineCount
    // And the width in pixels of the last line.
    val lastLineWidth = blueLayout.getLineWidth(blueLineCount - 1)
    // We will skip over the full lines with newline characters and pad out the last line
    // with spaces.
    val newLines = "\n".repeat(blueLineCount - 1)
    val spaceWidth = blackText.paint.measureText(" ")
    val padChars = " ".repeat((lastLineWidth / spaceWidth).toInt() + 1)
    blackText.text = "$newLines$padChars${blackText.text}"
}

Here is the result:

在此处输入图片说明

You may need to make some adjustments to the views to make this work, but this is the general idea.

Case 2 - One TextView and an ImageView with Text

In this case, the ImageView with text is constrained to the other ImageView and positioned below the TextView . How this is accomplished depends on your requirements.

One layout can be used for both cases. In case #1, the second ImageView would have its visibility set to "gone" or "invisible". In case #2, the black text TextView would have its visibility set to "gone" or "invisible".

I originally thought that a LeadingMarginSpan would be the way to go, but it runs into difficulties if the black text should start on any line but the first.


If you want to flow text around an ImageView this Stack Overflow question and answer(s) should help.

嗨,尝试将 flexWrap 属性设置为 wrap 的Google 的 FlexboxLayout

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM