I want to position views outside of a ConstraintLayout to animate them with a sliding animation. I've tried setting contraints like constraintBottom_toTopOf="parent" but the View stays inside the container.
Note that I want to achieve this with constraints to use built-in animations, not with in-code animations.
Any idea how I could do this ?
I'm using compile 'com.android.support.constraint:constraint-layout:1.1.0-beta1'
with Android Studio 3.0 Beta 7
This is a simple xml file that should place the view outside of the container :
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
android:background="#color/colorAccent">
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#color/colorPrimary"
app:layout_constraintBottom_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
But this is the result
This appears to be an issue with ConstraintLayout 1.1.0-beta1; It works as expected in ConstraintLayout 1.1.0-beta3.
Update to ConstraintLayout 1.1.0-beta3. I will also note that you need to constrain your view horizontally by doing something like the following.
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#color/colorPrimary"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="parent" />
On a side note, negative margins are not accepted in ConstraintLayout. See this Stack Overflow question regarding negative margins and ConstraintLayout.
In every view you can use negative margin, which will put the view outside of the parent view, and then set the clipping parameters.
android:clipChildren="false"
android:clipToPadding="false"
this will make the view not to clip.
I got another way to solve the problem:
1.Add a anchor(anchor_left) layout_constraintStart_toStartOf="parent".
2.Add YourView layout_constraintEnd_toStartOf="#+id/anchor_left"
That's it!
code:
<android.support.constraint.ConstraintLayout>
<View
android:id="#+id/anchor_left"
app:layout_constraintStart_toStartOf="parent"/>
<YourView
android:id="#+id/ll_left"
app:layout_constraintEnd_toStartOf="#+id/anchor_left"/>
</android.support.constraint.ConstraintLayout>
What I did is:
created a view of 0dp height inside the ConstraintLayout, e.g. "fakeView"
placed the new fakeView anchored at Top of the ConstraintLayout
when I need to hide a View, translate it outside the constraint..
change the constraint of the view you want to hide, in order to have BOTTOM connected to the Top of the FakeView.
I think you can use same technique to move object on the left of the fakeview or on the right.
One trick would be to set negative margin for the side you want, in the ConstraintLayout itself. This requires that other views that have constraint to that side be offset:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_marginBottom="-48dp">
<ImageButton
android:id="#+id/leftButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="72dp"
android:background="#drawable/shape_next_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageButton
android:id="#+id/rightButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="24dp"
android:background="#drawable/shape_previous_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Related
I have a View in a Constraint Layout and I would like that at the very beginning it should be outside of the screen (and then later slowly move into the scree from right to left). Now, I kind of need something like negative bias or margins.
I had a look at this question How to achieve overlap/negative margin on Constraint Layout?. The accepted answer using android:layout_marginTop="-25dp" does not have any effect (altough the top of the view is constrained and I use"androidx.constraintlayout:constraintlayout:2.1.3").
I tried the second most upvoted answer and used the code:
view.setTranslationX(view.getWidth() - 20);
This actually works. However, the problem is that when the Fragment is created you first see that the view is not on the left for a short period of time. This is not what I want. I would like to have the view beyond the right rim of the layout at the very very beginning such that it can later move into the layout.
Do you have any idea how I can do that? Ideally I would like to do this programmatically.
Update: Here is the code of the XML layout where a negative margin does not have any effect:
<?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"
android:background="#drawable/game_test_background"
tools:context=".MainActivity"
android:id="#+id/constraintLayout">
<ImageView
android:id="#+id/imageView_RedRectange_Test"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginTop="-1250dp"
app:layout_constraintWidth_percent="0.25"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.048"
app:srcCompat="#drawable/red_rectangle" />
<Button
android:id="#+id/button"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.102"
app:layout_constraintHorizontal_bias="0.373"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.745"
app:layout_constraintWidth_percent="0.12" />
</androidx.constraintlayout.widget.ConstraintLayout>
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();
There is a problem with setting the width of the button using app:layout_constraintWidth_percent when the ImageView has a negative margin. The problem should go away if you can set a definite width to the button (instead of 0dp).
The problem should also resolve if you set app:layout_constraintWidth_percent to a value such that the text of the button shows completely on one line.
Here is a simplified layout to demonstrate this issue. The ConstraintLayout has two views that are simply constrained to the parent to appear in vertical center of the layout. These two views have no dependencies on each other. In addition, the ImageView has a top margin of -250dp, so it should appear above the layout's vertical center.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_green_light">
<ImageView
android:id="#+id/redRectangle"
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_marginTop="-250dp"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/red_rectangle" />
<Button
android:id="#+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.12" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here is what happens then the width of the ImageView is changed from 0dp to a non-zero value of 1dp. When the width is set to 0dp, the negative margin seems to be ignored. It is only when the width is set to a non-zero value that the ImageView is correctly placed.
Changing the width of the button should have no effect on the placement of the ImageView; however, the button only appears in the proper position when the button has a non-zero width.
Here is what happens when the app:layout_constraintWidth_percent is increased so that the word "Button" is not cutoff.
Again, the placement of the ImageView should be independent of the width of the button. Instead, the button only appears in the correct position when the app:layout_constraintWidth_percent is set such that the word "Button" is not cutoff.
This is only an issue with negative margins. Positive margins work as expected.
This is a strange problem, so you may want to use one of the other solutions mentioned.
(ConstraintLayout version 2.1.3)
Im using a Constraintlayout with bias to fill the screen with multiple views. When I rotate the views they dont get resized to to fill the screen. My layout is more complicated but I created an example to show my problem.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/one"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#android:color/holo_orange_dark"
app:layout_constraintBottom_toTopOf="#+id/two"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:rotation="90"
android:background="#android:color/holo_green_light"/>
</FrameLayout>
<FrameLayout
android:id="#+id/two"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#android:color/holo_red_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/one">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_green_light" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
It doesn't really matter if I rotate the outer or the inner FrameLayout. I don't think I had this problem with LinearLayouts maybe the constraints are getting messed up by the rotation?
EDIT: Hmm looks like the same is happening when using a Linearlayout with weight as parent, so Im probably just doing something wrong here.
The view properties of rotation, translationX and translationY all take effect post-layout. I think that this is true for all view groups. In other words, the views are laid out as if rotation was not specified. Then, after layout, the rotation is applied. This is what you are seeing.
I don't have a reference for this but this problem comes up a lot on Stack Overflow.
Here is an example of this using translationY. Look at the "clarification" section at the top. See how the bottom view does not move even though it is constrained top-to-bottom with the view above? That is because it is positioned to the top view before the top view moves. translationY happens post-layout as does rotation.
This problem can be solved with (probably) a little coding. The exact solution depends on what you are trying to do.
I'm migrating some projects to AndroidX with Kotlin. I'm having some issues with ConstraintLayout, I already know that, according to the documentation:
Negative margins will not be supported in ConstraintLayout.
[...]
But I have the following situation:
I need to move up in 5dp the LinearLayout, however I need the height to continue to match the lower limit of the screen. That is, I move up 5dp and increment the height by 5dp.
As it's in the image, I've already tried translateY, but it just moves the entire view (not what I need). Also I can not create a view inside the id#top with height of 5dp and align with constraintTop_toTopOf, since they are part of different groups.
Is there any solution for this case?
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
The whole purpose of ConstraintLayout is to have a flat view hierarchy. Therefore, having LinearLayouts nested in defeats the purpose.
I suggest you get rid of the nested LinearLayouts and do everything using constraints.
I have a custom FrameLayout in my project which acts as a button since I did not want to to keep repeating same code.
The view works perfectly but when I need to arrange them horizontally constraining to each other, The center view does not follow the constraints and instead, It aligns to parent start overshadowing the other.
What should I do to my code to ensure the constraints work as expected?
The code is as below
dash_buttons.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.revosleap.wazalendo.utils.ui.DashButton
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/dashButtonLoan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dash_text="Pay"
app:dash_icon="#drawable/ic_pay"
android:id="#+id/dashButtonPay"
/>
<com.revosleap.wazalendo.utils.ui.DashButton
app:layout_constraintStart_toEndOf="#id/dashButtonPay"
app:layout_constraintEnd_toStartOf="#id/dashButtonAccount"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dash_text="Loan"
app:dash_icon="#drawable/ic_loan"
android:id="#+id/dashButtonLoan"
/>
<com.revosleap.wazalendo.utils.ui.DashButton
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#id/dashButtonLoan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dash_text="Account"
app:dash_icon="#drawable/ic_user"
android:id="#+id/dashButtonAccount"
/>
</android.support.constraint.ConstraintLayout>
The result
I finally figured it out. It seems Constraint Layout has some issues with custom views that use layout resource containing Linear Layout. To achieve my objective, I changed parent layout from Constraint layout to Frame layout and used gravity to maintain positions and all runs perfectly now.
]I'm using constraint layout in version 1.1.0 beta 6 (Which is way better than the stable 1.0.2 by the way...)
However, using constraintHeight_percent doesn't work for me in some case.
Here's what I want to achieve:
Place a button(bottom-button) with a fixed height at the bottom of the constraint layout
Place another button(top-button) between the top of the constraint layout, and above bottom-button.
Make the top-button final height to be half of its height.
Here's the 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"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#71B9DE">
<Button
android:id="#+id/bottomButton"
android:layout_width="0dp"
android:layout_height="150dp"
android:text="BOTTOM BUTTON"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:layout_width="0dp"
android:layout_height="0dp"
android:text="TOP BUTTON - The height should be 75dp!!"
app:layout_constraintBottom_toTopOf="#id/bottomButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
Here's the preview:
And here's how I expected it to be:
I don't understand why after using app:layout_constraintHeight_percent="0.5", the height of the top button is still 150DP and not 75DP.
It seems like app:layout_constraintHeight_percent="0.5" calculation is done related to the parent height, and not related to the button height itself, after it got constrained.
Btw, I'm not looking for other solutions (Using guidelines, barriers). I really try to figure out why it doesn't work.
Thanks for the help!
According to official reference document in the section 'MATCH_CONSTRAINT dimensions (Added in 1.1)':
layout_constraintWidth_percent and layout_constraintHeight_percent : will set the size of this dimension as a percentage of the parent
provided that the corresponding constraints are set to MATCH_CONSTRAINT (0dp)
You shoud use android:layout_width="match_parent" instead of 0dp