Allow TextView to grow until a certain point in constraint layout - android

There is TextView1 and TextView2. TextView2 should float on the right side of TextView1. TextView1 should grow to the right as long as the total width of both text views do not make TextView2 overlap with the box on the right. When this happens, TextView1 should wrap to a second line.
When there is only one TextView, this is achievable by setting TextView's width to 0dp and constraining the size to the box. But with two text views I don't know how to achieve this.

You can achieve this with the use of the following attributes:
app:layout_constraintHorizontal_bias="0": makes sure the first text view leaves no space on the left.
app:layout_constraintHorizontal_chainStyle="packed": removes spacing between items in the text view chain.
app:layout_constrainedWidth="true": allows the use of wrap_content on the text view while still allowing to wrap if text is too long.
Here's the layout:
<TextView
android:id="#+id/text_view_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="#id/text_view_2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Very long text in this text"
app:layout_constraintHorizontal_bias="0"
/>
<TextView
android:id="#+id/text_view_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintEnd_toStartOf="#id/box"
app:layout_constraintStart_toEndOf="#id/text_view_1"
app:layout_constraintTop_toTopOf="parent"
tools:text="Text"
/>
<View
android:id="#+id/box"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
I suggest you try removing each attribute to see what effect they have.

Related

constraintlayout - set a view padding depending on another view

I would like to know if I can set the title of TextView_1 to be centered of the parent view but ellipsize end against TextView_2 like picture below by using constraint layout. if the text in TextView_1 gets longer then, make it ellipsized. and below would be the case where I wanted to put "Text to be centered but ellipsize against TextView_2 when it gets longer".
what I have tried are
I programmatically tried to get the width of TextView_2 and set it to padding right of TextView_1. but failed since I wasn't able to get the width of TextView_2(I get 0) since it is set to be 0dp in constraint layout to be stretched.
I tried to find a way to set TextView_1 padding as TextView_2 size in xml file but that doesn't seem to be possible.
I have no more good idea to make it work. is there any work around for it? I will appreciate your help in advance.
You didn't post code, but I don't think you waited for the layout to occur to get the size of textView2. Here is some working code with the following XML. The code runs in the onCreateView() function of the Fragment. After layout, the width of TextView2 is set to the start/left padding of TextView1.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:text="Text to be centered but ellipsize against TextView_2 when it gets longer"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/textView2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView2"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/textView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
binding = DataBindingUtil.setContentView(requireActivity(), R.layout.fragment_main)
binding.root.doOnNextLayout {
binding.textView1.updatePadding(binding.textView2.width)
}

TextView can't wrap arround text in ConstraintLayout

I've got an issue with TextView in ConstraintLayout, the xml with constraints looks like this:
<TextView
...
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="20dp"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/section_title"
tools:text="Data Processing, Hosting, and Related Services"
/>
The whole TextView is styled and in style I'm using flag android:breakStrategy="balanced" so the TextView presents like this:
As you can see it's expanding it's width to fill the constraint and doesn't wrap around the text so the background doesn't display correctly. Anyone knows the solution?
Remove this tag app:layout_constraintEnd_toEndOf="parent"
Reason -
you have given constraint to textview which will align itself to end
of parent, so app:layout_constraintStart_toStartOf="parent" is enough
to align it to start of parent and it will wrap content as a
background
Example
<TextView
...
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="20dp"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/section_title"
tools:text="Data Processing, Hosting,\nand Related Services"
/>

Using wrap_content behavior and ellipsize if text too long

I have three views on my layout TextView1 TextView2 and ImageView.
TextView1 wraps content while TextView2 aligned to end of TextView1
I want to make TextView1 ellipsize in the end when its content too long while width of TextView1 TextView2 ImageView together have filled all width of layout
I've tried a lot of options to make it in xml with LinearLayout, RelativeLayout, ConstraintLayout and none of them gave me desired result.
The closest one is
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/card_item_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:gravity="start"
app:layout_constraintWidth_max="284dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="WWWWWWWWWWWWWWWWWWWWWWW"/>
<TextView
android:id="#+id/card_item_small_number"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingStart="#dimen/offset_6"
android:paddingEnd="#dimen/offset_6"
android:maxLines="1"
app:layout_constraintStart_toEndOf="#id/card_item_name"
app:layout_constraintEnd_toStartOf="#id/card_item_bank_logo"
app:layout_constraintTop_toTopOf="parent"
android:gravity="start"
tools:text="**** 5555"/>
<ImageView
android:id="#+id/card_item_bank_logo"
android:layout_width="wrap_content"
android:layout_height="#dimen/offset_24"
android:maxHeight="#dimen/offset_24"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#drawable/ic_language"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Key thing here is in TextView1 attributes
android:layout_width="0dp"
app:layout_constraintWidth_max="284dp"
BUT that means I have to calculate layout_constraintWidth_max value at run time, because width of TextView2 and ImageView are not fixed and depends on its values
Is there any way to make it ONLY in xml without 'magic' numbers ?
try
android:layout_weight="1"
You can work around from that to fit your desire width on the views.
To make this work, user LinearLayout with horizontal orientation.

How do I center a text inside a chain relative to the whole screen?

I want to create a user name centered TextView with an edit button to the right of the screen. If I specify the TextView to match the start/end of the parent, it will center. However, the text will overflow and paint over the button. I can chain one side of the text to the button, but then the text will not be centered. Here is the example code I have where tvName is not centered due to the button in the horizontal chain:
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="#dimen/pt_name_font_size"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#id/tvUserMsisdn"
app:layout_constraintEnd_toStartOf="#id/ibChangeName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/aivProfile"
tools:text="B"/>
<TextView
android:id="#+id/tvName2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="#dimen/pt_name_font_size"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#id/tvUserMsisdn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvName"
tools:text="A"/>
<ImageButton
android:id="#+id/ibChangeName"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="#dimen/default_margin"
app:layout_constraintBottom_toBottomOf="#id/tvName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#id/tvName"
android:background="#android:color/black"/>
This is what it looks like:
I can't use a horizontal bias, since the button has to remain with a static size, and the width of the screen may vary, as well as the size of the font. Ideally, I would be able to specify two app:layout_constraintEnd_toStartOf attributes, one for the whole width of the screen, so the text remains centered, and another one for the button, so it won't overflow.
Ideally, I would be able to specify two app:layout_constraintEnd_toStartOf attributes
I'm sure you already know this, but that is impossible.
The only thing you can do that is like that is to use a Barrier, but that's not helpful here because (in this case) that would be functionally identical to simply constraining the end to the start of the ImageButton.
The best thing you can do here, in my opinion, is to constrain the TextView's start and end to the parent, and then use padding to make sure that long text doesn't overlap the ImageButton. The button has a fixed width (28dp), and a fixed margin (#dimen/default_margin), so you can give the TextView left/right padding equal to 28dp + 2x default_margin. This will make sure that text wraps at least default_margin away from the left edge of the ImageButton.
Put both the TextView and the ImageButton inside a RelativeLayout:
<RelativeLayout
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvName2"
android:layout_alignParentStart="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="#+id/ibChangeName"
android:textSize="#dimen/pt_name_font_size"
android:textStyle="bold"
tools:text="A"/>
<ImageButton
android:id="#+id/ibChangeName"
android:layout_alignParentEnd="true"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="#dimen/default_margin"
android:background="#android:color/black"/>
</RelativeLayout>
This attribute for the TextView
android:layout_toStartOf="#+id/ibChangeName"
ensures that the TextView won't overlap with the ImageButton
Now you have to center the relative layout
If the ImageButton always has a fixed size (28dp in this case) you can use a Space widget with the same dimensions as the button and place it on the left edge of the parent. You can then chain the three Views together and set the chain's style to spread_inside. The TextView's width can be set to match_constraint and its gravity to center or use wrap_content and app:layout_constrainedWidth="true" so it doesn't overlap the other Views if it gets too big.
Example XML to get the general idea:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Space
android:id="#+id/space"
android:layout_width="28dp"
android:layout_height="28dp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintEnd_toStartOf="#id/textview"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Textview"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="#id/button"
app:layout_constraintStart_toEndOf="#id/space" />
<ImageButton
android:id="#+id/button"
android:layout_width="28dp"
android:layout_height="28dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/textview" />
</android.support.constraint.ConstraintLayout>

Align a set of views to the right of the largest view of those appearing in the right part of the screen

Can I use a ConstraintLayout to create a view that aligns children views to based on the largest child view?
Example:
Taking into account that the right Text printed can be larger in one of the rows, I'd like to have the progress bars be aligned to the largest Text on the right.
Is that possible? I can do it with nested LinearLayout but was wondering if ConstraintLayout solves this
Create a Barrier with start direction and reference all the IDs of the TextViews on the right. Constrain the end of each progress bar to the Barrier. The Barrier will be aligned to the start of the longest TextView.
Sample XML of how to achieve this:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Barrier
android:id="#+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="text1,text2"/>
<TextView
android:id="#+id/progress1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ProgressBar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="#id/barrier" />
<TextView
android:id="#+id/progress2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ProgressBar"
app:layout_constraintTop_toBottomOf="#id/progress1"
app:layout_constraintEnd_toStartOf="#id/barrier" />
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Longer Text"
app:layout_constraintTop_toBottomOf="#id/text1"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Result:
To prevent the left TextView from overlapping with other Views you need to constrain its end to progress bar, set horizontal bias to 0 so that it's aligned to its start constraint and also set app:layout_constrainedWidth="true" to its constraints are enforced when the width is set to wrap_content. It should look like this:
<TextView
android:id="#+id/foo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Foo"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#id/progress1"
app:layout_constraintTop_toTopOf="parent" />
It will cause the text to wrap to the next line when it reaches the progress bar. You can add ellipsis or limit the TextView to have the maximum of 1 line if you don't want the text to wrap.
Alternatively, you can just set the left TextView's width to 0 so it takes all available space to the left of the progress bar.

Categories

Resources