Position button on top-end of CardView - android

How can I add a button on top-end of CardView?
I have a solution but I don't like set a fixed height (ie 50dp) of button and than set margin_top (ie 25dp) of card_view.
Do you have other solutions?
<?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="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="#dimen/corner_radius"
app:cardElevation="2dp"
app:cardUseCompatPadding="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/btn">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="#+id/view_cover"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#ddd"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<com.google.android.material.button.MaterialButton
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginEnd="#dimen/dimen_16"
android:elevation="#dimen/dimen_2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

You can do it like following
<?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="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragments.LibraryFragment">
<androidx.cardview.widget.CardView
android:id="#+id/my_card"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:src="#android:drawable/ic_delete"
app:layout_constraintWidth_percent="0.08"
app:layout_constraintDimensionRatio="1:1"
app:tint="#color/redColor"
android:elevation="50dp"
app:layout_constraintTop_toTopOf="#id/my_card"
app:layout_constraintBottom_toTopOf="#id/my_card"
app:layout_constraintStart_toStartOf="#id/my_card"
app:layout_constraintEnd_toEndOf="#id/my_card"
app:layout_constraintHorizontal_bias="0.98"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
This will generate output like this
the image size will be based on the width of the screen which will be differ from device to device and it will resize according to it. and also it will be square due to we provided the ratio as 1:1

Looks like constraint layout doesn't allow negative margin(offset), so all you can do is workarounds.
There is another workaround, which i think is better than your example in terms of "intention". It goes like this:
Assuming your button is 50dp width/height.
Place Space element inside the constraint layout. Let's say width/height is 25dp(half of 50dp).
Align the Space element to the corner of the constraint layout. In case you want to put the button top end, then top of Space to top of constraint layout, and end of Space to end of constraint layout.
At this point, you virtually created "anchor" points where you can align other elements to, that is, the bottom and start of Space.
Align the start of the button to the start of Space, and the bottom of the button to the bottom of Space.
The button is now placed as if you would do layout_marginEnd/layout_marginBottom of -25dp.
The reason I think this is better is that the overlapping detail is no longer the constraint layout's concern, instead, it's the button and its neighboring element's.

Related

Constraint Layout with two chained TextViews doesn't render properly

I'm trying to create an layout which renders two TextViews packed together as in picture #1. Now, when first (red) TextView has more text than the allowed space it expands itself to fit it's constraints - which is an expected behaviour, see picture #2.
Now when i reverse the situation - make the second (violet) TextView expand I'm not getting similar result - picture #3. As we can see the second TextView doesn't respect the first TextView constraints.
The other thing that I've also found is that if we replace the order of TextViews in our *.xml file as "TextView red -> TextView violet" to "TextView violet <- TextView red" while keeping the constraints it works properly - picture 4 (but the previous case ie fails again).
I've used the latest constraint layout libraries:
// implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0-alpha2'
And the layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:background="#f00"
android:id="#+id/a"
android:layout_width="0dp"
android:layout_height="0dp"
android:textSize="50sp"
android:text="a"
app:layout_constraintHeight_default="wrap"
app:layout_constraintBottom_toTopOf="#id/b"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
/>
<TextView
android:background="#f0f"
android:id="#+id/b"
android:layout_width="0dp"
android:layout_height="0dp"
android:textSize="50sp"
android:text="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
app:layout_constraintHeight_default="wrap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#+id/a"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintVertical_chainStyle="packed"/
</androidx.constraintlayout.widget.ConstraintLayout>
If you do have an idea how to make two TextViews behave as in picture #1, #2 and #4 i would be very grateful.
You need to specify a minimum height constraint app:layout_constraintHeight_min="wrap" to both TextViews in order to make sure that both will at least wrap their content, in other words this will make any of the TextViews not to be greedy on one another.
Also this will keep both TextViews stretchable while maintaining the minimum height.
The only downside of this that both TextViews don't obey to the height constraints, you can see in below pic dashed line of height limits, also the top TextView text is cut. This is because both TextViews tends to wrap their content while keeping constraints at the same time.
In my trial, the padding is proportional to the size of the TextView and how big is the content of both of them.
A possible workaround to add padding at the top of top TextView, and at the Bottom of bottom Textivew
Another way to work on is to be strict to height constraint, and don't wrap height content by removing app:layout_constraintHeight_default="wrap" from both.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/a"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#f00"
android:paddingTop="0dp"
android:text="a"
android:textSize="50sp"
app:layout_constraintBottom_toTopOf="#+id/b"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/b"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#f0f"
android:paddingTop="0dp"
android:text="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbzzzzzzzzzzzzzzz"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/a" />
</androidx.constraintlayout.widget.ConstraintLayout>
Edit: misunderstood wanted behavior.
You have 2 options, use
app:layout_constraintHeight_min="minimumHeight"
or
app:layout_constraintHeight_percent="percentage/100"

Android sticky-footer: Align footer view to table, until it reaches screen size, then become fixed.at the bottom

This should be similar to an iOS tableview footer, also seen in various websites (sticky-footer).
I want to achieve the following:
A is a RecyclerView with variable number of rows.
When A is smaller than screen (or parent) size, B (footer) should be placed bellow the last row.
When A + B are bigger than screen size, then B becomes fixed at the bottom and A content is scrollable.
We are currently performing this with onMeasure functions that calculate all components heights in order to resize A accordingly.
I was wondering if there is an easier way to do it, maybe with ConstraintLayout.
Put A and B in a vertical packed chain with a bias of 0 to align it to the top. You also need to set app:layout_constrainedHeight="true" for the RecyclerView so that its constraints are taken into account when it gets too big to fit them (parent's height remains match_parent in this case):
<?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">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/A"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/B" />
<TextView
android:id="#+id/B"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Footer"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/A"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The above solution does not seem to work on Constraintlayout:2.0.0-beta2, looks like a bug introduced in that version. Works on 2.0.0-beta1 and 1.1.3.
Another way would be to set parent's height to wrap_content and then you can use the default chainstyle and remove the bias:
<?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="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/A"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/B" />
<TextView
android:id="#+id/B"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Footer"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/A"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
This solution works on all versions.
Just try ConstraintLayout, this should very well be possible, just fix Bs height and constrain it to the bottom and A and turn the bias up to top.

How can I make a recyclerView to take up to half the screen(max) in android constraint layout?

I have a screen that contains 2 views, a map(top) and a recycler(bottom)
The rules are simple .
the recycler view is allowed to extend up to the middle of the screen, if more space is needed then it should scroll instead, the map will occupy the rest of the space, Of course if the recycler has less elements then it should shrink leaving more space for the map ..
I am trying to achieve this using constraint layout, also I am trying to avoid solutions that involved calculations .
Check image below for more information on what I am trying to achieve :
Here is my code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
tools:context="com.qmic.itraffic.ui.activities.crowdsourcing.CrowdSourceReportingDetailsActivity">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/halfScreenGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/categories"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="#color/manatee"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/categories"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/halfScreenGuideline" />
</androidx.constraintlayout.widget.ConstraintLayout>
My Question is can I achieve this behaviour using xml only (constraint layout )?or I would need to do calculation ?
Could you please try the following code in your recyclerview xml
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
Change the height to wrap content and add the second the line. This way the recyclerview should have the height same as its content but never exceeds the guideline/contraint.
The answer by Akhil Soman is correct but missing one thing
app:layout_constraintVertical_bias="1.0"
Without it the RecyclerView was floating above the bottom of the screen leaving an empty space .
for reference here is the complete answer
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/categories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:clipToPadding="false"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/halfScreenGuideline"
app:layout_constraintVertical_bias="1.0" />
Also the suggestion by the Jaymin seems interesting and can fix this problem, but I haven't applied it because I already used Akil solution .

EditText grows and pushes other View off screen

I have a layout with two views that should behave like this:
On top is an EditText that should grow (and shrink) dynamically.
Right underneath is another view. The EditText grows until the other
View reaches the bottom of the parent layout, then it stops growing
and becomes scrollable instead.
An image that illustrates the desired behaviour can be found here (cannot upload it) :
The problem, it seems, is to limit the EditText to a certain height so it won't push the other View off the bottom of the screen. Or to give the other View an attribute that it always stays on screen, I don't know.
I tried several different approaches to solve it via xml. The one I attach simply works by limiting the number of lines in the EditText - which I would later have to change programmatically depending on device's resolution. So that's not really desirable.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<include
android:id="#+id/tripNotes_toolbar_layout"
layout="#layout/toolbar_details" />
<android.support.constraint.ConstraintLayout
android:id="#+id/tripNotes_constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="#style/CardStyle"
android:layout_gravity="top"
android:layout_marginLeft="#dimen/card_outer_margin_left"
android:layout_marginRight="#dimen/card_outer_margin_left">
<EditText
android:id="#+id/tripNotes_editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="#null"
android:hint="Put your notes here"
android:inputType="textMultiLine|textCapWords"
android:lines="12"
android:maxLength="1000"
android:maxLines="12"
android:minLines="1"
android:textColor="#color/grey_12"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/tripNotes_pictureGrid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tripNotes_editText"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_weight="1"/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
The actual result is that other View is pushed off screen if number of lines in EditText is not limited, but I would prefer a solution with alyout attributes.
You can wrap the edit text into a scroll view
Your layout would look like this :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<include
android:id="#+id/tripNotes_toolbar_layout"
layout="#layout/toolbar_details" />
<android.support.constraint.ConstraintLayout
android:id="#+id/tripNotes_constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/CardStyle"
android:layout_gravity="top"
android:layout_marginLeft="#dimen/card_outer_margin_left"
android:layout_marginRight="#dimen/card_outer_margin_left">
<ScrollView
android:id="#+id/tripNotes_editTextContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/tripNotes_pictureGrid">
<EditText
android:id="#+id/tripNotes_editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="#null"
android:hint="Put your notes here"
android:inputType="textMultiLine|textCapWords"
android:textColor="#color/grey_12" />
</ScrollView>
<View
android:id="#+id/tripNotes_pictureGrid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/tripNotes_editTextContainer"
app:layout_constraintTop_toBottomOf="#id/tripNotes_editTextContainer"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_weight="1"/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
Changes made :
Constraint layout height changed from match_parent to wrap_content
Edit text
removed app:layout_constraintTop_toTopOf="parent" (no longer needed since it is wrapped in scrollview)
removed maxLines, lines, minLines and maxLength attributes
Added ScrollView
Bottom View :
changed
app:layout_constraintStart_toStartOf="parent" to app:layout_constraintStart_toEndOf="#id/tripNotes_editTextContainer"
changed
app:layout_constraintTop_toBottomOf="#id/tripNotes_editText" to app:layout_constraintTop_toBottomOf="#id/tripNotes_editTextContainer"
The bottom view will be just under the Edittext and will go down until the bottom of the screen and the EditText will become scrollable

Put 2 views in a ConstraintLayout that's itself in another ConstraintLayout

I am trying to understand how Android's ConstraintLayout works, and in order to do so, I want to create a layout that would take 1/4 of the view height with a left/right/bottom margin of 25dp, and in this layout, put two views, the first one would take 70% of its height and the second one the remaining 30%.
To sum up this:
I tried this so far:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:layout_marginBottom="25dp"
app:layout_constraintDimensionRatio="w,1:4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" >
<View
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintDimensionRatio="w,7:10"
android:background="#color/red" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintDimensionRatio="w,3:10"
android:background="#color/light_blue" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
But instead I'm only having the bottom view (that should take 30% of the height) taking the whole layout space. What am I doing wrong?
Thanks for your help.
What you have:
Property app:layout_constraintDimensionRatio is "self dependable" , that is it only adjust width-to-height ratio of itself.
What you require:
If you're using ConstrainLayout 1.1.x you can use property app:layout_constraintHeight_percent , which takes values from 0 to 1.
Also, you might have to adjust constrains of these views top and bottom to be relative to each other.

Categories

Resources