How to achieve overlap/negative margin on Constraint Layout?
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>
How to use same technique of css negative margin in a layout?
Here you go:
<?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=".MainActivity"
tools:layout_editor_absoluteY="81dp">
<TextView
android:id="@+id/txt_home_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/box"
android:elegantTextHeight="true"
android:padding="30dp"
android:text="Welcome!"
android:textColor="#ffffff"
android:textSize="28sp"
tools:layout_editor_absoluteX="129dp"
tools:layout_editor_absoluteY="0dp" />
<android.support.v4.widget.Space
android:id="@+id/space"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="32dp"
app:layout_constraintBottom_toBottomOf="@+id/txt_home_title"
app:layout_constraintLeft_toLeftOf="@id/txt_home_title"
app:layout_constraintRight_toRightOf="@id/txt_home_title" />
<ImageView
android:id="@+id/home_logo"
android:layout_width="98dp"
android:layout_height="84dp"
android:scaleType="fitCenter"
android:src="@mipmap/ic_launcher"
app:layout_constraintHorizontal_bias="0.687"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/space" />
</android.support.constraint.ConstraintLayout>
Output:
Explanation:
We can not use negative margin in ConstraintLayout
as it is not officially supported so we need to use a workaround. Add an empty view i.e. Space
between ImageView
and TextView
and set android:layout_marginBottom="32dp"
to Space
view and you are done.
I followed this answer of CommonsWare.
ConstraintLayout, move a LinearLayout up (negatively)
It's tricky to get views to overlap in ConstraintLayout, but you can do it by adding an invisible view and constraining the overlapping view to the invisible view.
In this case the invisible view's bottom could be constrained to the bottom of the green LinearLayout, with a bottom margin of 5dp. The red LinearLayout can then have its top constrained to the bottom of the invisible view. This should give you 5dp of overlap.
Try copy-pasting the following into your constraint layout
<LinearLayout
android:id="@+id/green"
android:layout_width="0dp"
android:layout_height="100dp"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/holo_green_light" />
<View
android:id="@+id/dummyView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="5dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@id/green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<LinearLayout
android:id="@+id/red"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/dummyView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@android:color/holo_red_light" />
Note that a dimension of "0dp" means "match constraints" when set on a child view of a ConstraintLayout. This is not obvious, but is in fact documented here https://developer.android.com/reference/android/support/constraint/ConstraintLayout
How to position a view in Android constraint layout outside the screen at the beginning
Okay so to have a negative margin you can use translateX, translateY or TranslationZ.
in xml like so:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
android:translationX="-60dp"
android:translationY="-90dp"
android:translationZ="-420dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
or programmatically like so:
View view = ...;
view.setTranslationX(-60);
view.setTranslationY(-90);
view.setTranslationZ(-420);
Then in order to slowly bring it in from right to left you can use the animate() method like so:
View view = ...;
view.animate().setDuration(1000).translationX(-600).start();
margin end/right is not working on item in constraint layout
You can only set margins for a view if you have the constraint. Because you constrained your ImageViews start to the end of textView you can set the start margin for the image. If you reversed it and constrained the end of yout TextView to the ImageView you can set the margin in the TextView.
How to remove the margin of the view in the constraint layout when the anchor constraint is removed
You will want to adjust the margins in your layout to make use of "gone" margins. See
Margins when connected to a GONE widget.
Here is a simplified version of your layout as an example:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/SellerProfileContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:background="@android:color/holo_blue_light"
app:layout_constraintEnd_toEndtOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginTop="24dp">
<ImageView
android:id="@+id/SellerProfileImage"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_launcher_foreground"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/SellerProfile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="sellerFullName"
android:visibility="@{sellerFullName != null ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="@id/SellerProfileImage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/SellerProfileImage"
app:layout_constraintTop_toTopOf="@id/SellerProfileImage"
app:layout_goneMarginStart="0dp"
tools:text="Seller Profile Name" />
</androidx.constraintlayout.widget.ConstraintLayout>
I made adjustments to the margins of the two widgets. The key change is setting app:layout_goneMarginStart="0dp"
on the TextView. This will set the start margin to 0dp
when the image is gone
.
and to 16dp
when the image is visible
.
You should be able to accomplish this aspect of your layout without the use of data binding.
Related Topics
Android Background Drawable Not Working in Button Since Android Studio 4.1
How to Run a Service Every Day at Noon, and on Every Boot
Horizontalscrollview: Auto-Scroll to End When New Views Are Added
How to Make Drawerlayout to Display Below the Toolbar
Android Studio Fails to Build New Project, Timed Out While Wating for Slave Aapt Process
Using Onsaveinstancestate with Fragments in Backstack
How to Use Front and Back Camera at Same Time in Android
How to Write a Custom Filter for Listview with Arrayadapter
How to Get Number of Lines of Textview
Get Image from the Gallery and Show in Imageview
Highlight Listview Selected Row
How to Read Contacts in Android Using Realm
How to Decompile an APK or Dex File on Android Platform
How to Change Color of Android Listview Separator Line
Best Ocr (Optical Character Recognition) Example in Android
Streaming Audio from a Url in Android Using Mediaplayer