ConstraintLayout with growing TextViews claiming equal space if needed - android

Is it possible to in ConstrainLayout have two textviews constrained such that they take 50% of the horizontal space each if they need it, and if they don't the other grows to fill the space.
A Correct: When texts are short the textViews do not interfere with eachother.
B Correct: The short left textView yields space to the longer right one
C Correct: Share horizontal space equally and grow vertically
D Incorrect: Right textView grows on expense of the left textView.
E Incorrect: Right textView grows vertically rather than filling available horizontal space.
I've tried a lot of things. It think layout_width="wrap_content" or layout_constraintWidth_default="wrap" is a must since it is the textViews' only way to communicate how much space it wants.
Experimented with:
layout_constrainedWidth="true/false"
layout_constraintWidth_default="spread/wrap"
layout_constraintWidth_max="wrap"
layout_constraintHorizontal_weight="1" // with 0dp as width
Experimentation mostly with the textViews in a horizontal chain, since there is a symmetry in the problem I think a symmetric solution makes sense.
Has anyone managed this or is it just impossible? I do not know why it behaves as it does with the second element in the chain being 'heavier' than the first one forcing it to be the only one to grow vertically.

To solve your problem, you have to set the width of the TextViews to 0dp. I added a Barrier to the TextView at the left so that whenever the right TextView needs space, it will take the space of the left TextView. Try this code:
<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:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/text_barrier"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/text_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="textView1" />
</androidx.constraintlayout.widget.ConstraintLayout>

Barriers is what you are looking for in combination with chaining.
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constrainedWidth="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="#id/barrier"/>
<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="textView2" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="#id/barrier"/>

Use Constraint layout horizinatal chain property.
<?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:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#655643"
android:textSize="15sp"
android:textStyle="bold"
android:layout_marginTop="10dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintEnd_toStartOf="#+id/subtitle"
app:layout_constraintStart_toStartOf="parent"
tools:text="Dream Destinations sfsd sdfsdfdsfsdfsdfsdfsdfs" />
<TextView
android:id="#+id/subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#999999"
android:textSize="13sp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
app:layout_constraintTop_toTopOf="#+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/title"
tools:text="by Someone, 921 discoveriesdfdsfdsfsdffsfsfsdf" />
</androidx.constraintlayout.widget.ConstraintLayout>

Related

TextView exceed Constraint if text is too long in ConstraintLayout

I have one TextView aligned to the left and centered vertically. Two groups of ImageView and TextView are both aligned to the right, with two layout configurations, one with image on the right, another with image on the left.
The hello world text can be very long. I want it to expand to fill the whole width without covering up the left text.
I have added app:layout_constraintStart_toEndOf="#id/text1" to constraint the right group (image + text) not to overlap with the left text. However, it does not behave as I expected.
How to make it not overlapping using only ConstraintLayout?
Text1 will be covered up if the right text is too long, which is not expected. Be noted that the image on the second row is gone too.
code:
<?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:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Text1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/row1_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="#id/row1_image"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="#id/text1"
app:layout_constraintTop_toTopOf="parent"
tools:text="Hello World" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/row1_image"
android:layout_width="22dp"
android:layout_height="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/row1_text"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/ic_confirm" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/horizontal_barrier"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="row1_text,row1_image" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/row2_image"
android:layout_width="22dp"
android:layout_height="22dp"
app:layout_constraintEnd_toStartOf="#id/row2_text"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="#id/text1"
app:layout_constraintTop_toTopOf="#id/horizontal_barrier"
tools:src="#drawable/ic_confirm" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/row2_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/row2_image"
app:layout_constraintTop_toTopOf="#id/horizontal_barrier"
tools:text="Hello World" />
</androidx.constraintlayout.widget.ConstraintLayout>
expected to be like below if the right text is too long. It can achieved by LinearLayout and RelativeLayout
Kindly check the Constraintlayout version. Use app:layout_constrainedWidth="true"
with android:layout_width="wrap_content"
You can use Guidelines to stop your text from expanding more than needed.
let's take this layout for example:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="longgggggg texttttttttttttttttexttttttttttttttttexttttttttttttttttexttttttttttttttt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/guideline2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.18" />
And because of app:layout_constraintGuide_percent="0.18" and android:layout_width="0dp" on both text views the long textView will not exit its constraints.
I had a similar issue, the problem was that I was mixing left and start, so the view was constrained from Right to Left, but the left was set as constraintStartToParent.
Changing everything to start / end solved the issue.

One Textview overlaps another in ConstraintLayout

I have ConstraintLayout with two TextView inside:
<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="wrap_content">
<TextView
android:id="#+id/first"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/second"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="#+id/first"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
I want to place the first one at the top left-corner of parent container and to place the second one at the top-right parent's corner. But both textviews can have text with any length. And when first one has very long text it overlaps the second textview. I can solve this problem by wrapping both textviews in LinearLayout. But this way seems to me inelegant. Maybe there is another way to do it? I mean with ConstraintLayout's feautures
First of all, remove the wrap_content from your widths as this makes the left/right constraints irrelevant. Use 0dp in its place to make it adhere to the constraints' rules.
Then create a horizontal chain between the views and have it as spread, so that the views don’t overlap at any point and they also stay at the edges of the screen at all times.
Finally, align the texts accordingly so that the left one aligns to the start of the view and the right one aligns to the end. In the example below you see that no matter how long the text is, the views don’t overlap and stick to their sides.
NOTE: It is considered better practice to use start/end constraints (as in my code) instead of left/right in order to cater for devices with different text direction. You can also modify the code below by adding the appropriate margins to have the text farther away from the edges of the screen.
<?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:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/first"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
app:layout_constraintEnd_toStartOf="#+id/second"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="#tools:sample/lorem/random" />
<TextView
android:id="#+id/second"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAlignment="viewEnd"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toEndOf="#id/first"
app:layout_constraintTop_toTopOf="parent"
tools:text="#tools:sample/lorem/random" />
</androidx.constraintlayout.widget.ConstraintLayout>
use this
<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="wrap_content">
<TextView
android:id="#+id/first"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="chauhan"/>
<TextView
android:id="#+id/second"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="mehul"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<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="wrap_content">
<TextView
android:id="#+id/first"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/second"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="#+id/first"
app:layout_constraintRight_toRightOf="parent"
android:gravity="right"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
This way second TextView won't overlap first one for sure, but there might happen that first is too long so that there is no place for second one. If that could be the case I would recommend setting maxWidth to first TextView, so that in worst case scenario there is some space left for second TextView.
Also I added graviti to second one to keep text on right side of TextView.
<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="wrap_content">
<TextView
android:id="#+id/first"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="0dp"
app:layout_constraintRight_toLeftOf="#+id/second"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/second"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="#+id/first"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvFirst"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="#+id/tvSecond"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvSecond"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/tvFirst"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

ConstraintLayout Prevent Overlap of Top and Bottom Widgets

I am trying to create a layout with three groups of widgets. I want one group constrained to the top, one to the bottom, and one to float in the middle of the space between the two groups. The layout will be used in a fragment, so it could become squashed, especially when the keyboard is shown. I am having trouble figuring out how to prevent overlap of the two groups, while keeping the top and bottom constrained to the top and bottom of the layout.
I thought of several ways to do it, but I couldn't figure out how to implement any of the properly.
Using app:layout_constraintVertical_bias or app:layout_constraintVertical_weight to pull widgets together or spread them apart.
Using one chain, but having breaks in between the groups. I couldn't figure out how to split the chain part way through to allow the different groups to spread out.
Specify a minimum height that is dependent upon the contained widgets. (It will be contained in a ScrollView so it if the height is constrained it will work)
Create groups of packed chains where the packed chains are in a spread chain.
Or is there a better way than these to get what I want?
Note: I would prefer that the top and bottom groups aren't right against the parent layout, but I couldn't figure out how to get those groups to dynamically distance themselves from the parent layout without also spreading the group apart. I want the top and bottom groups close to the parent layout, but not necessarily right against it. It is better to have them right against the parent layout than close to the middle. Ideally I would be able to use app:layout_constraintVertical_bias or app:layout_constraintVertical_weight for this.
Code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" >
<EditText
android:id="#+id/edit_text_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/edit_text_horizontal_margin"
android:layout_marginRight="#dimen/edit_text_horizontal_margin"
android:layout_marginTop="#dimen/edit_text_vertical_margin"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/edit_text_2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:hint="Edit Text 1"
android:selectAllOnFocus="true" />
<EditText
android:id="#+id/edit_text_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/edit_text_horizontal_margin"
android:layout_marginRight="#dimen/edit_text_horizontal_margin"
android:layout_marginTop="#dimen/edit_text_vertical_margin"
android:layout_marginBottom="#dimen/edit_text_vertical_margin"
app:layout_constraintTop_toBottomOf="#id/edit_text_1"
app:layout_constraintBottom_toTopOf="#id/button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:hint="Edit Text 2"
android:selectAllOnFocus="true" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/edit_text_2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:enabled="false"
android:text="Button" />
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/progress_bar_margin"
app:layout_constraintTop_toBottomOf="#id/button"
app:layout_constraintBottom_toTopOf="#id/clickable_text_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:visibility="gone" />
<TextView
android:id="#+id/clickable_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/text_button_horizontal_margin"
android:layout_marginRight="#dimen/text_button_horizontal_margin"
android:layout_marginTop="#dimen/text_button_vertical_margin"
android:layout_marginBottom="#dimen/text_button_vertical_margin"
android:paddingLeft="#dimen/text_button_horizontal_margin"
android:paddingRight="#dimen/text_button_horizontal_margin"
android:paddingTop="#dimen/text_button_vertical_margin"
android:paddingBottom="#dimen/text_button_vertical_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="Clickable Text View"
android:clickable="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Images
- - - -
Here is what I have, and how I want it to look. - - - - - Here is the overlapping problem.
for the textview add a constraint top to bottom of the button ie app:layout_constraintTop_toBottomOf="#+id/button". IMO always constraint all 4 angles wherever possible; start top end bottom. In that way when your view is 'squashed', it will still adhere to the constraint set
Here, try 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="#+id/emailId"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="36dp"
android:hint="Enter email ID"
android:inputType="textEmailAddress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="36dp"
android:hint="Enter password"
android:inputType="textPassword"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/emailId" />
<Button
android:id="#+id/signInBtn"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="#color/colorAccent"
android:text="Sign in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/password" />
<TextView
android:id="#+id/analyticsLog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="Click me to create a log"
android:textColor="#android:color/holo_blue_dark"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I believe that you can use Guidelines together with app:layout_constraintHeight_percent to solve your problem.
Consider this layout:
<?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">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:enabled="false"
android:text="Button"
app:layout_constraintBottom_toTopOf="#+id/guideline3"
app:layout_constraintHeight_percent="0.1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/edit_text_2" />
<EditText
android:id="#+id/edit_text_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:hint="Edit Text 2"
android:selectAllOnFocus="true"
app:layout_constraintBottom_toTopOf="#id/button"
app:layout_constraintHeight_percent="0.1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/edit_text_1" />
<EditText
android:id="#+id/edit_text_1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:hint="Edit Text 1"
android:selectAllOnFocus="true"
app:layout_constraintBottom_toTopOf="#id/edit_text_2"
app:layout_constraintHeight_percent="0.1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="#id/clickable_text_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/button" />
<TextView
android:id="#+id/clickable_text_view"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:clickable="true"
android:gravity="center"
android:text="Clickable Text View"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHeight_percent="0.1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".35" />
Every view height is equal to 10% of the screen height, that's because of the app:layout_constraintHeight_percent="0.1" attribute. This will solve the overlapping problem for you because you will be able to tell your view what height to be relative to the screen size.
I was using guidelines as well with the app:layout_constraintGuide_percent=".35" attribute to tell the guideline were to be on the screen, by doing that I can constrain different views to it and you won't have to stick your views to the top of bottom of the screen as you mentioned (I would prefer that the top and bottom groups aren't right against the parent layout)
Your layout will look like this:(this is preview image for better understanding guidelines)
for who has same problem. use app:layout_constraintVertical_chainStyle="packed" with app:layout_constraintVertical_bias="1" to attach the view to botom. if use app:layout_constraintVertical_bias="0"the view will attach to top.
<TextView
...
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/button"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="1"/>

ConstraintLayout: Compound ImageView that stays in parent when text expands

Consider the following layout:
<android.support.constraint.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/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:padding="8dp"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Text" />
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="#id/text_view"
app:layout_constraintTop_toTopOf="parent"
tools:background="#android:color/black" />
</android.support.constraint.ConstraintLayout>
The image view (or button, or any other widget, important is that it has a fixed size) is aligned right/end of a TextView with a size of wrap_content, thus, the text itself only takes the space it needs.
What I now want is, when the text expands (aka if it's longer), that the button gets aligned to the right of the parent, and the text view only gets the width that is left and gets ellipsized.
At the moment, the image view is pushed outside and the text gets ellipsized once it fills the whole parent.
I tried to fix this by adding a endToEnd="parent" constraint the the image and setting the horizontal bias to 0 (see code), but that doesn't work.
Any suggestions on what I could do instead?
In order to prevent the ImageView from getting pushed outside the parent you need to constrain the end of the TextView to the start of the ImageView to create a chain. Now to ensure that the TextView only takes the space it needs but also has its constraints enforced, you need to add app:layout_constrainedWidth="true" attribute to your TextView.
If you want the ImageView to stay immediately to the right of the TextView can use packed chain style with a horizontal bias of 0.
If you want the ImageView to be aligned to the right of the parent you can use the spread_inside chain style without bias.
The resulting XML with above changes might look like this:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:padding="8dp"
android:textSize="18sp"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Text" />
<ImageView
android:id="#+id/image_view"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/text_view"
app:layout_constraintTop_toTopOf="parent"
tools:background="#android:color/black" />
</android.support.constraint.ConstraintLayout>
EDIT: As requested in the comment, here's how it would work with a Barrier sparating the 3 TextViews and the ImageView. In this case you don't specify the constraints for the ends of the TextViews thus you no longer have them chained horizontally. Instead, you create a Barrier with the direction being the end of all TextViews that are referenced in the Barrier. This will ensure that the Barrier is always at the end of the widest TextView. The last thing to do is to constrain the start side of the ImageView to the Barrier.
Example XML:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:padding="8dp"
android:textSize="18sp"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintBottom_toTopOf="#id/text_view2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Text1" />
<TextView
android:id="#+id/text_view2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:padding="8dp"
android:textSize="18sp"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintBottom_toTopOf="#id/text_view3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/text_view1"
tools:text="Text2" />
<TextView
android:id="#+id/text_view3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:padding="8dp"
android:textSize="18sp"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/text_view2"
tools:text="Text3" />
<android.support.constraint.Barrier
android:id="#+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="text_view1,text_view2,text_view3" />
<ImageView
android:id="#+id/image_view"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/barrier"
app:layout_constraintTop_toTopOf="parent"
tools:background="#android:color/black" />
</android.support.constraint.ConstraintLayout>

Constraint Layout Getting a default top margin for imageview

I am trying to create a layout using constraint layout, with an ImageView on top, a button in the ImageView, a TextView below it and then another TextView below it. Following is the xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
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="wrap_content"
android:layout_margin="10dp"
app:cardElevation="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/news_image1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="0dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="#+id/news_title1"/>
<ImageButton
android:id="#+id/news_share_button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:src="#drawable/share_button_big"
app:layout_constraintBottom_toBottomOf="#+id/news_image1"
app:layout_constraintRight_toRightOf="#+id/news_image1"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"/>
<TextView
android:id="#+id/news_title1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|start"
android:layout_alignParentBottom="true"
android:lines="3"
android:ellipsize="end"
app:layout_constraintTop_toBottomOf="#+id/news_image1"
app:layout_constraintBottom_toTopOf="#+id/news_read_more1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textColor="#color/colorPrimaryText"
android:layout_margin="#dimen/news_cell0_textview_margin"
android:textSize="12sp"
android:typeface="monospace" />
<TextView
android:id="#+id/news_read_more1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|start"
android:layout_alignParentBottom="true"
android:lines="1"
android:ellipsize="end"
app:layout_constraintTop_toBottomOf="#+id/news_title1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:textColor="#color/read_more_text_color"
android:text="#string/news_read_more"
android:layout_margin="#dimen/news_cell0_textview_margin"
android:textSize="10sp" />
</android.support.constraint.ConstraintLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
Everything is correct except for a small margin on top of the first ImageView. Whatever I do I cannot get rid of that margin. See the image below.
Please note the margin between the top of the ImageView and the card, that is what is troubling me.
Your news_image, news_title1, and news_read_more1 views form a chain. Apparently, though I cannot find documentation on this, all views in a vertical chain will share vertical margins. In other words, applying a layout_marginTop or layout_marginBottom attribute to one of those three views will wind up applying it to all three of them.
You will have to re-allocate your margins, keeping this in mind.
Edit
Looks like the behavior is a little more sophisticated than I thought. First of all, it looks like it only applies to views with the spread "chain style" (which is the default). Second, it looks like top margin is applied to the view it is specified on as well as all views above that one in the chain, while bottom margin is applied to the view it is specified on as well as all views below that one in the chain. Finally, it appears that margins are cumulative (so if you had 10dp top margin on your bottom view and 20dp top margin on your middle view, the final result would be 30dp on your top view, 30dp on your middle view, and 10dp on your bottom view).
As for how to solve this problem in your specific case? You should be able to use left/right margins without issue. And then probably you should use bottom margin on your top view to space the three views out.
Edit #2
Muthukrishnan's answer made me realize that you could solve this problem by simply removing the chain from your views. If you delete the app:layout_constraintBottom_toTopOf="#+id/news_title1" constraint from your ImageView, that will break the chain and now the vertical margins aren't shared.
Thanks to the great starter by Ben P, I managed to figure out a solution. There are three(plus one weighed) chaining styles available in ConstraintLayout. According to this great tutorial the chaining styles are explained as:
Spread: The views are evenly distributed. E.g.
app:layout_constraintHorizontal_chainStyle=”spread”
app:layout_constraintVertical_chainStyle=”spread”
Spread inside: The first and last view are affixed to the constraints on each end of the chain and the rest are evenly distributed. E.g.
app:layout_constraintHorizontal_chainStyle=”spread_inside”
app:layout_constraintVertical_chainStyle=”spread_inside”
Packed: The views are packed together (after margins are accounted for). You can then adjust the whole chain’s bias (left/right or up/down) by changing the chain’s head view bias. E.g.
app:layout_constraintHorizontal_chainStyle=”packed”
app:layout_constraintVertical_chainStyle=”packed”
Weighted: When the chain is set to either spread or spread inside, you can fill the remaining space by setting one or more views to “match constraints” (0dp). By default, the space is evenly distributed between each view that's set to "match constraints," but you can assign a weight of importance to each view using thelayout_constraintHorizontal_weight and layout_constraintVertical_weight attributes. If you're familiar with layout_weight in a linear layout, this works the same way. So the view with the highest weight value gets the most amount of space; views that have the same weight get the same amount of space.
spread is the default chaining style. I changed it to spread_inside so that the first and last views are affixed to the constraints on each end of the chain(hence obeying the margins provided). The xml now looks like:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
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="wrap_content"
android:layout_margin="10dp"
app:cardElevation="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/news_image1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="0dp"
app:layout_constraintVertical_chainStyle="spread_inside"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="#+id/news_title1"/>
<ImageButton
android:id="#+id/news_share_button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:src="#drawable/share_button_big"
app:layout_constraintBottom_toBottomOf="#+id/news_image1"
app:layout_constraintRight_toRightOf="#+id/news_image1"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"/>
<TextView
android:id="#+id/news_title1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|start"
android:layout_alignParentBottom="true"
android:lines="3"
android:ellipsize="end"
app:layout_constraintVertical_chainStyle="spread_inside"
app:layout_constraintTop_toBottomOf="#+id/news_image1"
app:layout_constraintBottom_toTopOf="#+id/news_read_more1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textColor="#color/colorPrimaryText"
android:layout_margin="#dimen/news_cell0_textview_margin"
android:textSize="12sp"
android:typeface="monospace" />
<TextView
android:id="#+id/news_read_more1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|start"
android:layout_alignParentBottom="true"
android:lines="1"
android:ellipsize="end"
app:layout_constraintVertical_chainStyle="spread_inside"
app:layout_constraintTop_toBottomOf="#+id/news_title1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:textColor="#color/read_more_text_color"
android:text="#string/news_read_more"
android:layout_margin="#dimen/news_cell0_textview_margin"
android:textSize="10sp" />
</android.support.constraint.ConstraintLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
Try this, I remove app:layout_constraintTop_toTopOf="parent" in your layout it works
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
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="wrap_content"
android:layout_margin="10dp"
app:cardElevation="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/news_image1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<ImageButton
android:id="#+id/news_share_button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:src="#drawable/ic_menu_share"
app:layout_constraintBottom_toBottomOf="#+id/news_image1"
app:layout_constraintRight_toRightOf="#+id/news_image1"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"/>
<AliasTextView
android:id="#+id/news_title1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|start"
android:layout_alignParentBottom="true"
android:lines="3"
android:ellipsize="end"
app:layout_constraintTop_toBottomOf="#+id/news_image1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textColor="#color/colorPrimaryText"
android:layout_margin="#dimen/news_cell0_textview_margin"
android:textSize="12sp"
android:typeface="monospace" />
<TextView
android:id="#+id/news_read_more1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|start"
android:layout_alignParentBottom="true"
android:lines="1"
android:ellipsize="end"
app:layout_constraintTop_toBottomOf="#+id/news_title1"
app:layout_constraintLeft_toLeftOf="parent"
android:textColor="#color/read_more_text_color"
android:text="#string/news_read_more"
android:layout_margin="#dimen/news_cell0_textview_margin"
android:textSize="10sp" />
</android.support.constraint.ConstraintLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>

Categories

Resources