Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve overlap/negative margin on Constraint Layout?

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.

like image 571
bond Avatar asked Mar 23 '17 19:03

bond


People also ask

Can we give margin in negative Android?

No, you should not use negative margin .

How can we solve missing constraints in constraint layout?

Constraint errors Without constraints, the objects in your app would likely jump out of position when the app is loaded or the device is rotated. To automatically apply any missing constraints you can press the 'Infer Constraints' button at the top of the editor.

How can we use barrier in constraint layout?

To define a Barrier , you can select one or more View components from the “Design” view, open the “Guidelines” menu and select the Barrier . If you want to add it directly in the XML, you can use the following code snippet: The resulting layout looks like the screenshot of the “Design” layout editor view from below.

What is vertical bias in constraint layout?

Bias, in terms of ConstraintLayout , means "if there is extra room, slide the widget in this direction along the axis". The default bias is 0.5, meaning that the widget is centered in the available space.


2 Answers

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.

enter image description here

<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:

enter image description here

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:

enter image description here

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> 
like image 107
Cheticamp Avatar answered Sep 26 '22 09:09

Cheticamp


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"

like image 45
Amir Khorsandi Avatar answered Sep 24 '22 09:09

Amir Khorsandi