So in my recent interview I was asked what if within a ConstraintLayout which has multiple child Views supports part of the Views LTR and RTL change and part of the Views to ignore it. Like the images below:
As you can see, blue views change their direction based on Views' layout direction but the Red Green and Yellow ones keep there position relative to each other, but align their (collective) start and end based on the layout direction to different View.
I understand you can set up the blue Views simply by using start and end attributes instead of left and right. But how do you keep the order of the multicolored Views same but at the same time reposition them alongside other Views? While making sure there is no deeper hierarchy than the parent ConstraintLayout.
I realize I may not be making much sense here, I just can't think of another way to convey the question.
Interesting question. I don't know of any way to specify that part of a layout should remain LTR when all the other parts go RTL. I presume that you are looking for an XML-only solution.
Something to keep in mind is that the left-to-left, right-to-left constraints are still valid. Normally, these would just be replaced by start-to-start and end-to-start constraints. So, with this in mind and making some assumptions about the layout, the following works:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="#+id/view"
android:layout_width="100dp"
android:layout_height="300dp"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:background="#android:color/darker_gray"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/view2"
android:layout_width="239dp"
android:layout_height="75dp"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:background="#android:color/holo_blue_bright"
app:layout_constraintStart_toEndOf="#+id/view"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/box1"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="24dp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
android:background="#android:color/holo_orange_light"
app:layout_constraintRight_toLeftOf="#+id/box2"
app:layout_constraintLeft_toLeftOf="#+id/view2"
app:layout_constraintTop_toBottomOf="#+id/view2" />
<View
android:id="#+id/box2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="24dp"
android:background="#android:color/holo_red_light"
app:layout_constraintRight_toLeftOf="#+id/box3"
app:layout_constraintLeft_toRightOf="#+id/box1"
app:layout_constraintTop_toTopOf="#+id/box1" />
<View
android:id="#+id/box3"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="24dp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
android:background="#android:color/holo_green_light"
app:layout_constraintRight_toRightOf="#id/view2"
app:layout_constraintLeft_toRightOf="#+id/box2"
app:layout_constraintTop_toTopOf="#+id/box2" />
</androidx.constraintlayout.widget.ConstraintLayout>
There is one trick: layout_constraintHorizontal_chainStyle has to be set on the first and last view in the horizontal chain. There is also a tendency for the designer to change the left/right attributes back to start/end.
IRL, I would just wrap the blocks in a view group and be done with it. I think that it would be easier to maintain and not be prone to break.
Wrap the multicolored views in single view and make that view as parent for your other view's constraints.
Related
I have a widget that, no matter what constraints I place upon it and other widgets, including the addition of barriers, always positions itself at the top of the layout.
This is a fairly simple arrangement of two rows of two elements each, not aligned column wise. The first element in each row is a TextView label, the second an input (Spinner).
There is also a lone TextView title above the first row stretching all the way across. By my understanding and previous experience with constraint layout, this shouldn't require a barrier between the rows, and that was my initial version.
This is the design view, where the selected element ("Credentials") is supposed to be in the second row but instead appears above the first row, over top of the title TextView ("PKIX"):
Actual result in the emulator looks much the same. The selected "Credentials" element is the fourth of five elements in the XML layout below. All of the other elements are in the right place.
<?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">
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/bottomborder"
android:text="PKIX"
android:textAlignment="center"
android:layout_marginHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/addsrv_trust_lbl"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:text="Trust"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_trust_spin"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_lbl"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_spin"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:paddingHorizontal="10sp"
android:text="Credentials"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_cred_spin"
app:layout_constraintTop_toBottomOf="#+id/addsrv_trust_lbl"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_cred_spin"
/>
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_cred_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_trust_spin"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I'm perplexed. The addsrv_cred_lbl TextView ("Credentials") is:
Start aligned with parent.
End aligned with the addsrv_cred_spin spinner, which appears correctly positioned;
this alignment is reciprocated to create a horizontal chain. They are also baseline
aligned.
Top aligned with the bottom of the TextView above it, addsrv_trust_lbl.
This alignment is also reciprocated.
There's no bottom alignment yet (there's another row to go); bottom aligning it with the parent makes no difference unless I bottom align the spinner from the same row, in which case the result goes from bad to worse.
Since this did not work, I tried to use a barrier between the rows. If I use it as a "top", with the second row widgets as the constraint referents, the barrier appears at the top, above the title, regardless of what constraints are used to position it below the first row. Used as a "bottom", with the first row widgets referenced and the second row chained below it (which is more logical), things are a little bit better in that the barrier appears in the right place -- but the "Credentials" widget is still up top.
The design view of this looks exactly the same as the previous one except the barrier is visible below the first row. In the XML, I aslo added optimizationLevel="none" after having read this can help with misbehaving barriers (but it made no difference). There's also a few stylistic elements added back here (such as font size) I removed for brevity before.
<?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"
app:layout_optimizationLevel="none"
>
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/bottomborder"
android:backgroundTint="#color/tbar"
android:text="PKIX"
android:textAlignment="center"
android:textSize="#dimen/addsrv_bigfont"
android:textColor="#color/titleText"
android:layout_marginHorizontal="10sp"
app:layout_constraintBottom_toTopOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:text="Trust"
android:textSize="#dimen/addsrv_fontsz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_trust_spin"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toTopOf="#+id/addsrv_bar1"
app:layout_constraintHorizontal_chainStyle="packed"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBottom_toTopOf="#+id/addsrv_bar1"
/>
<androidx.constraintlayout.widget.Barrier
android:id="#+id/addsrv_bar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="addsrv_trust_lbl,addsrv_trust_spin"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_lbl"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Credentials"
android:textSize="#dimen/addsrv_fontsz"
app:layout_constraintBaseline_toBaselineOf="#+id/addsrv_cred_spin"
app:layout_constraintEnd_toStartOf="#+id/addsrv_cred_spin"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_bar1" />
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_cred_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_bar1"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Am I correct in observing that some of the constraints on addsrv_cred_lbl are being completely ignored? Doesn't topToBottom mean that the top of the widget is aligned with the bottom of the other? Instead, it seems simply to mean that they will be connected with a squiggly, potentially curved and convoluted line in the design view, and the spacial relation of the two widgets is arbitrary, such that the semantic logic might as well be inverted, "top = bottom, bottom = top", etc.
Please note that I do not want to use absolute values to position anything. If the only way to get this to work is to do that, constraint layout seems a complete waste of time even in this simple case, and I'd rather just stack some liner layouts.
The problem is that Spinner doesn't have a baseline. You were trying to tie it to the baseline of the item inside the Spinner is my guess - ConstraintLayout can't reach children of its children.
You can check it via the design tab with a right click. TextViews will show an option "Show baseline" but the Spinner doesn't.
Also snippet from the doc
Align the text baseline of a view to the text baseline of another
view.
That's what baselines are for, if you want two TextViews connect together so they don't have the height where the text starts messed up.
I think there is a tiny flaw in your approach to the chain. You were setting the top constraint of both elements in each row to the bottom of the previous row(or title in the first row). Even if the Spinner would have a baseline, this would make the label off-centered in relation to the Spinner(slightly higher because the baseline of a text is higher than the actual bottom of the view).
I think the best approach in these types of layouts is to have one guiding element(which is also the element of the chain) that represents the row and let other elements be positioned in relation to it.
<?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">
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="PKIX"
android:textAlignment="center"
android:layout_marginHorizontal="10sp"
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/addsrv_trust_spin"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:text="Trust"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_trust_spin"
app:layout_constraintTop_toTopOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toBottomOf="#+id/addsrv_trust_spin"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_trust_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_pkix_title"
app:layout_constraintBottom_toTopOf="#+id/addsrv_cred_spin"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Credentials"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/addsrv_cred_spin"
app:layout_constraintTop_toTopOf="#+id/addsrv_cred_spin"
app:layout_constraintBottom_toBottomOf="#+id/addsrv_cred_spin"
/>
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="#+id/addsrv_cred_lbl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/addsrv_trust_spin"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
NOTE: I added the last bottom constraint to the parent and "spread" to the chain for demonstration but also know that if you don't have the bottom of the last view constrained to something - it's not a chain.
Working with ConstraintLayout is easy if you obey few simple rules:
Create one chain. That means Views hooking to each other reciprocally, all the way.
Now that you have a working chain, you can manipulate it with layout_constraintVertical_bias and layout_constraintVertical_chainStyle. If changing those does nothing, it means your chain is broken.
hook remaining Views to ones laid out by the chain
every control must have 4 constraints: top, bottom, start and end
do not create competing chains and try to force them into working together.
Spinner cannot have baseline, only TextView and its descendants have it. Spinner is AdapterView, so it can contain whatever you can imagine.
BTW: don't use #+id to refer to existing ids. Plus means creating new id, so if you make a typo it will create new id that refers to nothing instead of error "there's no such id".
Here's an example: top label and Spinners form the main chain and side labels are positioned each to their Spinner:
<?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"
>
<TextView
android:id="#+id/addsrv_pkix_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10sp"
android:background=""
android:text="PKIX"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#id/addsrv_trust_spin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintVertical_chainStyle="packed"
/>
<TextView
android:id="#+id/addsrv_trust_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Trust"
app:layout_constraintBottom_toBottomOf="#id/addsrv_trust_spin"
app:layout_constraintEnd_toStartOf="#id/addsrv_trust_spin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/addsrv_trust_spin"
app:layout_constraintVertical_bias="1.0"
/>
<Spinner
android:id="#+id/addsrv_trust_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#id/addsrv_cred_spin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/addsrv_trust_lbl"
app:layout_constraintTop_toBottomOf="#id/addsrv_pkix_title"
app:layout_constraintVertical_bias="0.0"
/>
<TextView
android:id="#+id/addsrv_cred_lbl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="10sp"
android:text="Credentials"
app:layout_constraintBottom_toBottomOf="#id/addsrv_cred_spin"
app:layout_constraintEnd_toStartOf="#id/addsrv_cred_spin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/addsrv_cred_spin"
app:layout_constraintVertical_bias="1.0"
/>
<Spinner
android:id="#+id/addsrv_cred_spin"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/addsrv_cred_lbl"
app:layout_constraintTop_toBottomOf="#id/addsrv_trust_spin"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I'm having a problem as am newbie, I want to put my TextViews according to the background image, i did it well, all good when tested app in virtual device, But when i tested it on my real device, TextView is at some other place (slightly downwards) to what I was expecting.
Is there any way to stretch the background image so that our XML code shows same display results on all devices (with different resolutions).
I just want same design results as shown on android studio Design tab.
Example :-
i want this result on all devices
am getting this on my real device
Please guys suggest the best way to do so.
My XML Layout 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"
android:background="#drawable/main_bg"
tools:context=".MainActivity">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="245dp"
android:text="#string/app_name2"
android:textColor="#color/colorPrimary"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="#string/Admin"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView" />
<EditText
android:id="#+id/editTextTextEmailAddress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:background="#drawable/rounded_box"
android:backgroundTint="#android:color/white"
android:elevation="1dp"
android:ems="10"
android:hint="Email"
android:inputType="textEmailAddress"
android:padding="9dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView"
app:layout_constraintVertical_bias="0.39" />
<EditText
android:id="#+id/editTextTextPassword"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="19dp"
android:layout_marginEnd="24dp"
android:ems="10"
android:hint="Password"
android:padding="9dp"
android:background="#drawable/rounded_box"
android:backgroundTint="#android:color/white"
android:elevation="1dp"
android:inputType="textPassword"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editTextTextEmailAddress" />
<Button
android:id="#+id/button"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="167dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="156dp"
android:text="Log In"
android:background="#drawable/rounded_corners"
android:textColor="#android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editTextTextPassword" />
</androidx.constraintlayout.widget.ConstraintLayout>
For this ConstraintLayout is a very good choice. how? Let's see
First, You've not provided your layout file completely so I don't know what you're doing.
Now, To position views according to any device, you should resort to scale independent solutions like using bias, setting-up different dimen values as per screen sizes and connecting widgets to each other using Constraints so they don't free float to any position when screen size changes.
Using Bias and Percent - Try to minimize use of fixed margin values like 20dp, 30dp and use Vertical/Horizontal bias, width_percent, height_percent and 0dp with it. 0dp acts as fill_contraint in ConstraintLayout.
As I can see in the pictures, you've five widgets except background, One button, Two EditTexts and two TextViews.
So, constraint button to bottom and top of parent and give it a vertical bias of 0.8 or 0.9.
As:
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.8"
app:layout_constraintWidth_percent="0.4"
/>
<!--Vertical bias will place it on 80% height of the screen and width_percent will
assign it 40% width of the screen. This will remain same in any size of the screen.-->
Now, Constraint Both editTexts to the button using Bottom_toTopOf and give the second one a margin of approx 50dp. The button will always stay on 80% of the screen and both the editText will always stay above the button. And constraint the 'GK Quiz' TextView by giving it a vertical_bias of 0.4/0.45/0.5 (whatever you prefer) and constraint the second textview to its bottom.
This is how you define a layout that will stay on same place in every screen size.
Defining custom dimen.xml - For this you can check this question out. If you don't want to mess with custom values, you can resort to two easy libraries - SDP(For layout Size) and SSP(For Text Size) which provide all the custom values which stays same in every screen size. I use these libraries so I know they work well. There's a medium article on these - How to build for different Android screen sizes using a single layout resource file.
Using Constraints - Remember, the moment you use margins or x/y values to position a widget on screen, you should be aware that they can mess up in any screen size. So, you should always constraints layout with each other to create a tight pack preventing the free flow of the layout elements. By free flow, I mean the different positions on screen in different sizes.
ConstraintLayout is most powerful layout available out there I believe and it has many ways to tackle the issues of different screen sizes. It also supports Animation using its subclass MotionLayout. Read these official docs, you'll learn more.
instead of this use a framelayout and put imageview in it with height and width of match parent and use gravity center. use gravity center for image view.
I have a simple layout of horizontally chained views with spread_inside chain style. When I try to move the views using the bias attribute to desired position I've found out that bias attribute is ignored.
Here is layout for reference:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<View
android:id="#+id/view_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#android:color/black"
app:layout_constraintEnd_toStartOf="#id/view_2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/view_2"
android:layout_width="90dp"
android:layout_height="90dp"
android:background="#android:color/black"
app:layout_constraintEnd_toStartOf="#id/view_3"
app:layout_constraintStart_toEndOf="#id/view_1"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/view_3"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="#android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintStart_toEndOf="#id/view_2"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Here I would like to move the view_3 closer to view_2 using layout_constraintHorizontal_bias attribute. How can I achieve that?
Horizontal biasing does not work if you are using a horizontal chain among your views (as you're giving biasing in the same axis, vertical biasing would work if there is a horizontal chain and vice-versa); except for the case if you want to apply it on your created chain's head view (which is the left-most view in a horizontal chain and the top-most view in a vertical chain); which is not your case, here. Also, the applied biasing on the head view of the chain only works if the selected chain style is packed. So, you should try and find some other workaround to achieve your desired UI and ignore the use of chain (here).
For more information, refer: Build a Responsive UI with ConstraintLayout
I hope my answer helps you.
You can change first view (chain head view) like this:
<View
android:id="#+id/view_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#android:color/black"
app:layout_constraintEnd_toStartOf="#+id/view_2"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent" />
and set all chain position relative to parent via layout_constraintHorizontal_bias, but inside chain this doesn't work.
Is it possible to achieve negative margin on constraint layout to achieve overlap?
I am trying to have a image centered on the layout and have a Text view such that it overlaps a by x dp. I tried setting negative margin value but no luck.
It would be great if there is a way to achieve this.
Update
ConstraintLayout now supports negative margins with version 2.1.0-alpha2. Simply state
android:layout_marginTop="-25dp"
for a negative 25dp margin. (This will only work if the top of the view is constrained. A margin has no effect in ConstraintLayout if the margin's side is not constrained.)
Clarification: The answer below remains valid, but I want to clarify a couple of things. The original solution will place a view with a de facto negative offset with respect to another view as stated and will appear in the layout as shown.
Another solution is to use the translationY property as suggested by Amir Khorsandi here. I prefer that solution as simpler with one caveat: The translation occurs post-layout, so views that are constrained to the displaced view will not follow the translation.
For example, the following XML displays two TextViews immediately below the image. Each view is constrained top-to-bottom with the view that appears immediately above it.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="150dp"
android:layout_height="150dp"
android:tint="#388E3C"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_action_droid" />
<TextView
android:id="#+id/sayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name."
android:textAppearance="#style/TextAppearance.AppCompat.Large"
app:layout_constraintTop_toBottomOf="#+id/imageView"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintStart_toStartOf="#+id/imageView" />
<TextView
android:id="#+id/sayIt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say it."
android:textAppearance="#style/TextAppearance.AppCompat.Large"
app:layout_constraintEnd_toEndOf="#+id/sayName"
app:layout_constraintStart_toStartOf="#+id/sayName"
app:layout_constraintTop_toBottomOf="#id/sayName" />
</androidx.constraintlayout.widget.ConstraintLayout>
Now, let's translate the "Say my name" TextView up by 50dp by specifying
android:translationY="-50dp"
This produces the following:
The "Say my name" TextView has shifted up as expected, but the "Say it" TextView has not followed it up as we might expect. This is because the translation occurs post-layout. Although the view moves post-layout, it can still be made clickable in the new position.
So, IMO, go with translationX and translationY for negative margins in ConstraintLayout if the caveat above doesn't affect your layout; otherwise, go with the space widget as outlined below.
Another caveat: As stated by Salam El-Banna in a comment to another answer, translationX will not be a good solution for RTL layouts since the sign of the translation will dictate the direction of the shift (left/right) regardless of the RTL or LTR nature of the layout.
Original answer
Although it doesn't appear that negative margins will be supported in ConstraintLayout, there is a way to accomplish the effect using the tools that are available and supported. Here is an image where the image title is overlapped 22dp from the bottom of the image - effectively a -22dp margin:
This was accomplished by using a Space widget with a bottom margin equal to the offset that you want. The Space widget then has its bottom constrained to the bottom of the ImageView. Now all you need to do is to constrain the top of the TextView with the image title to the bottom of the Space widget. The TextView will be positioned at the bottom of the Space view ignoring the margin that was set.
The following is the XML that accomplishes this effect. I will note that I use Space because it is lightweight and intended for this type of use, but I could have used another type of View and made it invisible. (You will probably need to make adjustments, though.) You could also define a View with zero margins and the height of the inset margin you want, and constrain the top of the TextView to the top of the inset View.
Yet another approach would be to overlay the TextView on top of the ImageView by aligning tops/bottoms/lefts/right and make suitable adjustments to margins/padding. The benefit of the approach demonstrated below is that a negative margin can be created without a lot of computation. That is all to say that there are several ways to approach this.
Update: For a quick discussion and demo of this technique, see the Google Developers Medium blog post.
Negative Margin for ConstraintLayout XML
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#mipmap/ic_launcher" />
<android.support.v4.widget.Space
android:id="#+id/marginSpacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="22dp"
app:layout_constraintBottom_toBottomOf="#+id/imageView"
app:layout_constraintLeft_toLeftOf="#id/imageView"
app:layout_constraintRight_toRightOf="#id/imageView" />
<TextView
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/marginSpacer" />
</android.support.constraint.ConstraintLayout>
Another way is using translationX or translationY like this:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:translationX="25dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
it will work like android:layout_marginRight="-25dp"
Negative margins have never been officially supported in RelativeLayout. Negative margins will not be supported in ConstraintLayout. [...]
-- Romain Guy on Jun 8, 2016
Follow these two issues:
https://code.google.com/p/android/issues/detail?id=212499
https://code.google.com/p/android/issues/detail?id=234866
This is what I figured out after hours of trying to find a solution.
Let us consider two images, image1 and image2. Image2 is to be placed on top of image1 positioned to the bottom-right side.
Overlapping Views Example
We can use Space widget for overlapping views.
Constraint the Space widget's four sides with the four sides of the image1 respectively. For this example, constraint the image2's left side with the Space widget's right side and the image2's top side with the Space widget's bottom side. This will tie image2 with the Space widget and since the Space widget is constrained from all the sides, we can define required horizontal or vertical bias which will move image2 as required.
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Player">
<ImageView
android:id="#+id/image1"
android:layout_width="250dp"
android:layout_height="167dp"
android:src="#android:color/holo_green_dark"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Space
android:id="#+id/space"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/image1"
app:layout_constraintEnd_toEndOf="#+id/image1"
app:layout_constraintHorizontal_bias="0.82"
app:layout_constraintStart_toStartOf="#+id/image1"
app:layout_constraintTop_toTopOf="#+id/image1"
app:layout_constraintVertical_bias="0.62" />
<ImageView
android:id="#+id/image2"
android:layout_width="82dp"
android:layout_height="108dp"
android:src="#android:color/holo_green_light"
app:layout_constraintStart_toEndOf="#+id/space"
app:layout_constraintTop_toBottomOf="#+id/space" />
</android.support.constraint.ConstraintLayout>
Additionally, to position image2 on the center-bottom of image1, we can constraint image2's left and right sides with Space widget's left and right sides respectively. Similarly, we can place image2 anywhere by changing image2's constraints with Space widget.
I found a way to do it much simpler.
Basically have the ImageView, then on the Text View add top constraint to match the top constraint of the image and just add the margin top of the TextView to match to achieve the -ve margin type behavior.
This will help many
In my case i want my design like this:
Means i want my image is display half of their width so the basically i need negative margin of half of the actual image width but my whole layout in constraint layout and constraint layout does not allowed negative margin so i achieved this with below code
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
android:src="#drawable/ic_launcher_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/guideline"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="50dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
So that ImageView will end at the starting of the guideline. and the effect is same as like negative margin at the start of 50dp.
And also if your view's width is not fixed and it's in percentage so that you can place guideline with percentage and achieve whatever effect you want
Happy Coding:)
You only need to use Space widget in your layout
<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/negative_margin"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toLeftOf="parent"/>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Widget who needs negative margin"
app:layout_constraintTop_toBottomOf="#+id/negative_margin"
app:layout_constraintLeft_toLeftOf="#+id/negative_margin" />
Place Background View Behind Subject View
I wanted to use negative margin to add a view behind a subject view that is proportionally bigger than the subject view. The solution I found was to scale android:scaleX="1.2" and android:scaleY="1.2" the background view while constraining it to all sides of the subject.
<View
android:id="#+id/subjectBackground"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleY="1.2"
android:scaleX="1.2"
app:layout_constraintBottom_toBottomOf="#+id/subjectView"
app:layout_constraintEnd_toEndOf="#+id/subjectView"
app:layout_constraintStart_toStartOf="#+id/subjectView"
app:layout_constraintTop_toTopOf="#+id/subjectView" />
This is an old question yet very much asked, the fastest way to achieve this is by constraining the top and bottom to the side of the view you want to anchor to, like so:
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="55dp"
android:layout_height="55dp"
app:layout_constraintBottom_toBottomOf="#+id/parent_view_id"
app:layout_constraintTop_toBottomOf="#+id/parent_view_id"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
This will center it in the bottom line of the view, centered horizontally.
One can try this way, this is much simpler
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MyProfileFragment">
<ImageView
android:id="#+id/imageViewUserPic"
android:layout_width="#dimen/dp60"
android:src="#mipmap/ic_launcher"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="20dp"
android:layout_height="wrap_content">
</ImageView>
<ImageView
android:id="#+id/imageViewEdit"
app:layout_constraintBottom_toBottomOf="#+id/imageViewUserPic"
android:src="#drawable/ic_edit_red_round"
app:layout_constraintEnd_toEndOf="#+id/imageViewUserPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>
The layout will be like this..
this is my soluation
<com.oven.test.avatar
android:id="#+id/imageview_a"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginTop="28dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.oven.test.smallicon
android:id="#+id/small_icon_overlap_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="#+id/imageview_a"
app:layout_constraintTop_toTopOf="#+id/imageview_a"
app:layout_constraintVertical_bias="1"
android:layout_marginBottom="20dp"/>
Using translationX and translationY may works for your situation.
<TextView
android:id="#+id/tvText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text"
android:translationX="-15dp"
android:translationY="10dp"
app:layout_constraintEnd_toEndOf="#+id/imageView"
app:layout_constraintTop_toTopOf="#+id/imageView" />
A Simple Way.
I'm not sure best way.
Just wrap using LinearLayout
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<View
android:layout_width="wrap_content"
android:layout_marginLeft="-20dp"
android:layout_height="wrap_content"/>
</LinearLayout>
Background
Google has announced a new layout called "ConstraintLayout" that's supposed to be the ultimate layout, that could replace all of the layouts while staying flat (without nested layouts) and have better performance.
The problem
Thing is, I barely see any tutorials for it that could help me on this matter, other than the video presented on Google IO.
What I am trying to do is, given that I have a vertically-centered LinearLayout within another layout - convert them both into a single ConstraintLayout.
After all, this is the purpose of this new layout...
The layout I wish to deal with looks like this:
Notice that the views in the center are only centered vertically, and that the 2 textViews are to the right of the ImageView, which is also centered vertically.
This all works well with RelativeLayout, which has the LinearLayout of the 2 TextViews, but I wish to know how to convert them into a single ConstraintLayout.
Here's a sample XML of what I've shown:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
android:minHeight="?attr/listPreferredItemHeightSmall">
<ImageView
android:id="#+id/appIconImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginEnd="4dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="4dp"
android:layout_marginStart="2dp"
android:adjustViewBounds="true"
android:src="#android:drawable/sym_def_app_icon"
tools:ignore="ContentDescription"/>
<LinearLayout
android:id="#+id/appDetailsContainer"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="#+id/appIconImageView"
android:layout_toLeftOf="#+id/overflowView"
android:layout_toRightOf="#+id/appIconImageView"
android:layout_toStartOf="#+id/overflowView"
android:orientation="vertical">
<TextView
android:id="#+id/appLabelTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:text="label"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textDirection="locale"
tools:ignore="HardcodedText,UnusedAttribute"/>
<TextView
android:id="#+id/appDescriptionTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:minLines="3"
android:text="description"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textDirection="locale"
tools:ignore="HardcodedText,UnusedAttribute"/>
</LinearLayout>
<ImageView
android:id="#+id/overflowView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:padding="10dp"
app:srcCompat="#drawable/ic_more_vert_black_24dp"
tools:src="#drawable/ic_more_vert_black_24dp"
tools:ignore="ContentDescription"/>
<ImageView
android:id="#+id/isSystemAppImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#+id/overflowView"
android:layout_alignLeft="#+id/overflowView"
android:layout_alignParentBottom="true"
android:layout_alignRight="#+id/overflowView"
android:layout_alignStart="#+id/overflowView"
android:adjustViewBounds="true"
android:scaleType="centerInside"
app:srcCompat="#drawable/ic_warning_black_24dp"
tools:ignore="ContentDescription"
tools:src="#drawable/ic_warning_black_24dp"/>
</RelativeLayout>
What I tried
I tried to read some articles and watch some videos of Google :
https://codelabs.developers.google.com/codelabs/constraint-layout/index.html#0
https://www.youtube.com/watch?v=sO9aX87hq9c
https://youtu.be/csaXml4xtN8?t=1693
That didn't help, so I tried to using it, hoping I will find out how to use it myself.
But I can't find out how to do it. I tried using the feature to convert the layouts, but this makes a huge mess of the views and puts additional margins that I don't want to have.
The question
How can I convert the 2 layouts into a single ConstraintLayout ?
Take a look at my answer here.
ContraintLayout contains a feature - Chains - that makes it possible to implement what you are asking:
Chains provide group-like behavior in a single axis (horizontally or
vertically).
A set of widgets are considered a chain if they a linked together via
a bi-directional connection
Once a chain is created, there are two possibilities:
Spread the elements in the available space
A chain can also be "packed", in that case the elements are grouped together
As for your case, you'll have to pack your label and description TextViews and center them in you parent vertically:
(make sure you use a version of ConstraintLayout that supports chains)
<?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">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintBottom_toTopOf="#+id/button"
app:layout_constraintLeft_toRightOf="#+id/imageView2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"/>
<TextView
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Button\nMkay"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/imageView2"
app:layout_constraintTop_toBottomOf="#+id/textView"/>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#mipmap/ic_launcher"/>
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#mipmap/ic_launcher"/>
<ImageView
android:id="#+id/imageView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:srcCompat="#mipmap/ic_launcher"/>
</android.support.constraint.ConstraintLayout>
Update 25-06-2019 (#Saeid Z):
Now in constraint layout 1.1.3 we must use app:layout_constraintHorizontal_chainStyle="packed" instead of app:layout_constraintVertical_chainPacked="true"
Set app:layout_constraintVertical_bias="0.5" to the views that need to be centered vertically, bias attribute only works if you specify the constraints for the boundaries (e.g. top and bottom for vertical bias, left and right for horizontal bias)
An example:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/constraintLayout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="#id/constraintLayout"
app:layout_constraintBottom_toBottomOf="#id/constraintLayout"
app:layout_constraintVertical_bias="0.5" />
</android.support.constraint.ConstraintLayout>
Got it working in my layout here: https://github.com/hidroh/tldroid/blob/master/app/src/main/res/layout/activity_main.xml, pretty much similar layout, though I position things at 1/3rd of screen height.
EDIT: This answer had been written before chains became available. Please use chains now, see above answer: https://stackoverflow.com/a/40102296/1402641
For now I believe your only choice would be to wrap the two text views in another layout - probably linear layout best fits this situation.
But the team behind constraint layout said they want to introduce "virtual containers", which serve exactly this use case: you group two or more views together and set a constraint (like centring vertically) on the container. The idea is that it is not a full nested layout inside of constraint layout, but just something that constraint layout uses to position it's children - hence it should provide better performance than nesting.
They mention it in their I/O talk (linked to the exact time). So I guess stay tuned.
To center something vertically or horizontally, set an opposing constraint on the layout.
Centered Vertically
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
Centered Horizontally
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
Take a look at mine example (Center components in ConstraintLayout)
For now you could center "image" (constrain left-top-bottom), constrain "label" top to "image" top, constrain "description" top to "label" bottom.
In example below i have matched button height with two textviews to the right (which is your case). Other textviews are constrained as on the link above.
UPDATE: Answering to your comment below:
I have installed your app and this is only i can think of currently. Since it is a ViewHolder layout, layout_height can be set to wrap_content, or you can fix it if you'd like to. I can send you xml if you want, i dont want to flood the answer.
Top TextView left constraint is constrained to right constraint of ImageView. Also, top TextView -> top constraint is constrained to top of container, so is right. Bottom TextView is constrained to bottom of container. TextViews in the middle are constrained to match width of top TextView and got no connection with ImageView.