ContraintLayout: Optional top view - android

I want to make the following design using ConstraintLayout. The screen should be devided into a top section (50% of screen), and a bottom section (50% of screen). The top section should be able to hide according to some application logic, making the bottom section use the remaining blank space on top.
My layout is as follows:
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="#+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="#android:drawable/ic_input_add" />
<android.support.constraint.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView" />
Comparison image showing on the left side how the layout looks with both sections visible. On the right side the top section is gone but the bottom RecyclerView does not stretch to use the top space. I added padding to the ImageView and RecyclerView to better illustrate the relationship between the views.

You can set equal vertical weights for both views in the chain so each occupies 50% of the space. If you set the top view's visibility to GONE in code or in XML, the bottom view will fill the remaining space.
<?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">
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/recyclerView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#android:drawable/ic_input_add"
app:layout_constraintVertical_weight="1" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView"
app:layout_constraintVertical_weight="1" />
</android.support.constraint.ConstraintLayout>

Related

Bottom item cut in reyclerview in android

Hey I am working in constraint layout with recylerview. My bottom item is cut in the screen. I read this stack overflow post. I don't want to use relative layout or linear layout. Can someone guide me how to fix this in constraint layout.
abc.xml
<?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.appcompat.widget.SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
app:closeIcon="#drawable/ic_cancel"
app:layout_constraintBottom_toTopOf="#+id/exploreScroll"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="0.0" />
<HorizontalScrollView
android:id="#+id/exploreScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:scrollbars="none"
app:layout_constraintBottom_toTopOf="#+id/exploreList"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/searchView">
<com.google.android.material.chip.ChipGroup
android:id="#+id/exploreChips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipSpacingHorizontal="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:singleLine="true"
app:singleSelection="true" />
</HorizontalScrollView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/exploreList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/exploreScroll" />
</androidx.constraintlayout.widget.ConstraintLayout>
My view cut from
UPDATE
#Zain after your suggestion i tried in my xml any my HorizontalScrollView is going behind my RV. I am adding my blueprint and you can see clearly that, HorizontalScrollView is going behind. After removing app:layout_constraintBottom_toTopOf="#+id/exploreList" from the HorizontalScrollView.
2nd suggestion try
Disclaimer Using a wrap_content height with vertical RecyclerView
can have impact on performance in terms of recycling views; specially
if the height is going to change frequently. Check this article
for more illustration.
So, the first step is to designate the RecyclerView height or to constraint it; from the constraints you want it to expand to the bottom; so use 0dp for that. But in order to make the minimum height to wrap content of the RecyclerView (in case that the items don't exceed the screen height); you can set the default height constraint to wrap with app:layout_constraintHeight_default="wrap" constraint.
Then remove app:layout_constraintBottom_toTopOf="#+id/exploreList" from the HorizontalScrollView, this actually made the bottom item of the RV hide (your main issue); because it is an over-constraint; the HorizontalScrollView tends to push the RV to the bottom while the RV tends to push the HorizontalScrollView to the top.
This will solve the main issue; but when the items are fully accommodated by the screen (no scrolling in the RV), then it will be biased in the middle; to fix this use the bias with app:layout_constraintVertical_bias="0.0" to be biased to the top.
Adding this in place into 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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
app:closeIcon="#drawable/ic_cancel"
app:layout_constraintBottom_toTopOf="#+id/exploreScroll"
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" />
<HorizontalScrollView
android:id="#+id/exploreScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/searchView">
<com.google.android.material.chip.ChipGroup
android:id="#+id/exploreChips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipSpacingHorizontal="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:singleLine="true"
app:singleSelection="true" />
</HorizontalScrollView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/exploreList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="20dp"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_default="wrap"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/exploreScroll" />
</androidx.constraintlayout.widget.ConstraintLayout>

Constrain max size of RecyclerView

I'm putting together a screen with 3 controls stacked vertically. Specifically, a RecyclerView sandwiched between two TextView. I have two situations I am trying to address.
When few items are displayed in the RecyclerView the 3 items should be packed towards the top of the screen with blank space BELOW them.
When many items are displayed in the RecyclerView the full screen will be used with the last TextView along the bottom of the screen and scrolling in the center RecyclerView.
I'm struggling to get the position of the last TextView correct as it either gets pushed off the screen or buried behind the RecyclerView if there are many items in the RecyclerView. What I need is a way to tell the RecyclerView to wrap contents, but stop growing when it starts to push the TextView off of the screen.
Below is my layout, any suggestions?
<?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">
<TextView
android:id="#+id/topItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#+id/middleItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/middleItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintBottom_toTopOf="#+id/bottomItem"
app:layout_constraintTop_toBottomOf="#+id/topItem" />
<TextView
android:id="#+id/bottomItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|top"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#+id/middleItem" />
</androidx.constraintlayout.widget.ConstraintLayout>
Try the following:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/topItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is the top item."
app:layout_constraintBottom_toTopOf="#+id/middleItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/middleItem"
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbars="none"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="#+id/bottomItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/topItem"
tools:itemCount="3" />
<TextView
android:id="#+id/bottomItem"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal|top"
android:text="This is the bottom item."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/middleItem" />
</androidx.constraintlayout.widget.ConstraintLayout>
With three items in the RecyclerView:
With 50 items in the RecyclerView:
The key changes are:
Added app:layout_constraintVertical_bias="0.0" to the top TextView to position the chain always at the top;
Added app:layout_constrainedHeight="true" to the RecyclerView to make sure views don't go off-screen;
Changed match_parent to 0dp and set the horizontal constraints for direct children of the ConstraintLayout.
Changed the RecyclerView's height to '0dp'.
Update: Although the above works, it is a little overdone. As noted in the comments, the same effect can be accomplished by simply setting the height of the RecyclerView to 0dp.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/topItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is the top item."
app:layout_constraintBottom_toTopOf="#+id/middleItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/middleItem"
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbars="none"
app:layout_constraintBottom_toTopOf="#+id/bottomItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/topItem"
tools:itemCount="3" />
<TextView
android:id="#+id/bottomItem"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal|top"
android:text="This is the bottom item."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/middleItem" />
</androidx.constraintlayout.widget.ConstraintLayout>

Android WebView overlaps with other views

I have a simple web view in between image and button. For some reason, if I put a long text, the web view is overlapping with the logo and the button. It works for a short text. I used constraint layout. It seems that the web view is expanding beyond the parent view.
Please see the pictures.
Below is my layout 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="wrap_content">
<ImageView
android:id="#+id/iv_logo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/card_big_margin"
android:src="#drawable/login_cashnetusa_color"
android:tint="#color/white"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<androidx.cardview.widget.CardView
android:id="#+id/cv_splash_screen"
style="#style/CardTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/card_normal_outer_margin"
android:layout_marginTop="#dimen/card_normal_outer_margin"
android:layout_marginRight="#dimen/card_normal_outer_margin"
android:layout_marginBottom="#dimen/card_normal_outer_margin"
app:layout_constraintBottom_toTopOf="#id/btn_cta"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/iv_logo">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv_header"
style="#style/CardContent.CustomBlack.Bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/card_normal_margin"
android:text="#string/dummy_full_name"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<WebView
android:id="#+id/wv_update_text"
style="#style/CardContent.White"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="#dimen/card_normal_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/tv_header" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="#+id/btn_cta"
style="#style/Button.OrangeGradient"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/card_normal_margin"
android:layout_marginRight="#dimen/card_normal_margin"
android:layout_marginBottom="#dimen/card_item_normal_margin"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="#id/tv_skip"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="#string/dummy_btn_ok" />
<TextView
android:id="#+id/tv_skip"
style="#style/CardContent.White"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/card_normal_margin"
android:text="#string/skip"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The problem lies in here:
<androidx.cardview.widget.CardView
android:id="#+id/cv_splash_screen"
style="#style/CardTheme"
android:layout_width="match_parent"
<-- change layout:height from wrap_content to some specific height let it be 300-400dp -->
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/card_normal_outer_margin"
android:layout_marginTop="#dimen/card_normal_outer_margin"
android:layout_marginRight="#dimen/card_normal_outer_margin"
android:layout_marginBottom="#dimen/card_normal_outer_margin"
app:layout_constraintBottom_toTopOf="#id/btn_cta"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/iv_logo">
or the second option is you can use minHeight and maxHeight in your cardview or it's child layout which is Constraint layout to prevent it from expanding on full screen
and if you have long texts to read use ScrollView inside cardview.
As you have set the height of your CardView to wrapContent it will expand to the content that is put in it, what you can do is set app:layout_constrainedHeight="true" that will prevent it from expanding beyond its bounds.
Note that you do have to set up the view bound chaining properly for this to work, ie set app:layout_constraintTop_toX and app:layout_constraintBottom_toX on all the views in the 'chain' from the top of the view through to the bottom.
so in your code:
<androidx.cardview.widget.CardView
android:id="#+id/cv_splash_screen"
style="#style/CardTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/card_normal_outer_margin"
android:layout_marginTop="#dimen/card_normal_outer_margin"
android:layout_marginRight="#dimen/card_normal_outer_margin"
android:layout_marginBottom="#dimen/card_normal_outer_margin"
<!-- add this line --> app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="#id/btn_cta"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/iv_logo">

ConstraintLayout - how to keep circle from pushing other views off the page? check minimum dimension?

I am trying to set up a layout for a counting app, which has a large circular button slightly above the centre of the screen and a counter display below it. I'm having trouble keeping the circle circular, entirely on the screen, and not overlying the other view in all situations.
The setup I'm currently using is a ConstraintLayout with two TextViews. The button TextView uses an xml oval as its background, and is set to be circular with the "layout_constraintDimensionRatio" attribute set to one. In portrait mode the width is set to 80% of the available space, and all is well when the screen is fairly standard in normal use.
The problem occurs if the available screen dimensions for the app are more square so that the vertical dimension is smaller than the horizontal dimension. In this case the width is still set first so my circle covers the other view or partially slips off screen.
Currently in the landscape layout I have the timer off to one side. Ideally in the landscape layout I would keep the button centred and the counter to the right, but to stop increasing the size of the button if there is not enough space for the timer.
I think that ideally I would set the layout up to check whether the horizontal or the vertical space is shorter initially, then set the smaller dimension first. Is this possible? Or perhaps is there a better approach to achieving my desired layout?
Any help would be really appreciated,
Thank you,
Katie
This is the default xml 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"
android:background="#android:color/white"
tools:context=".ui.CounterFragment">
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="#string/content_description_background_image"
android:scaleType="fitStart"
android:src="#drawable/dog_image_jpg_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
tools:visibility="visible" />
<TextView
android:id="#+id/timer_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/timer_display"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/guidelineHorizontal" />
<TextView
android:id="#+id/counter_button"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/circle_selector"
android:contentDescription="#string/counter_button_content_description"
android:text="#string/counter_text"
app:layout_constraintBottom_toTopOf="#+id/timer_display"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.375"
app:layout_constraintWidth_percent=".8" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is the landscape 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"
android:background="#android:color/white"
tools:context=".ui.CounterFragment">
<ImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="#string/content_description_background_image"
android:scaleType="fitStart"
android:src="#drawable/dog_image_jpg_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
tools:visibility="visible" />
<TextView
android:id="#+id/timer_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/timer_display"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/counter_button"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/counter_button"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/circle_selector"
android:contentDescription="#string/counter_button_content_description"
android:text="#string/counter_text"
app:layout_constraintBottom_toBottomOf="#id/guidelineHorizontal"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toStartOf="#id/guidelineVertical87"
app:layout_constraintHeight_percent="0.8"
app:layout_constraintStart_toEndOf="#id/guidelineVertical12"
app:layout_constraintTop_toTopOf="#id/guidelineHorizontal" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical75"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.75" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.125" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guidelineVertical87"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.875" />
</androidx.constraintlayout.widget.ConstraintLayout>
As you suggest, the primary issue with your layout is the percentage width/height set at 80% and driving the rest of the layout. You are losing control of the circle height and nothing keeps it from growing to cover other views.
Take a look at ConstraintLayout chains. They are a powerful tool and will let you tie your views together so they don't trounce one another. They will help you solve the overlay problem.
You will still want to set the width of the circle to 80% of the width or height depending on the orientation of the device. I assume that you want the side margins to be such that the circle can be 80% of the view but will allow the circle to be smaller if it needs to fit the screen and not overlap the other views. One way to do this is to define two Space widgets that are 10% of the layout width and 10% high. Place one in the upper left corner of the layout and the other in the lower right. Constrain the circle to these Space widgets on the left, top and right. Place the circle in a vertical chain with the TextView below.
Here is a mock up of what it would look like. You will have to work with your layout to get it right, but these are some concepts that should help. (Is seems to me that this can also be done without the Space widgets, but that solution is not occurring to me right now. I'll post back if it dawns on me.)
The XML follows the GIF.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<TextView
android:id="#+id/timer_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/timer_display"
android:textSize="40sp"
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/counter_button" />
<TextView
android:id="#+id/counter_button"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#drawable/circle"
android:text="#string/counter_text"
app:layout_constraintBottom_toTopOf="#+id/timer_display"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toStartOf="#+id/spaceBottomRight"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/spaceStart"
app:layout_constraintTop_toBottomOf="#+id/spaceStart"
app:layout_constraintVertical_bias="0.375"
app:layout_constraintVertical_chainStyle="packed" />
<Space
android:id="#+id/spaceBottomRight"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.10"
app:layout_constraintWidth_percent="0.10" />
<Space
android:id="#+id/spaceStart"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.10"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.10" />
</androidx.constraintlayout.widget.ConstraintLayout>

ConstraintLayout: Create a button that fills space after a RecyclerView

I have a horizontal RecyclerView inside a ConstraintLayout. I want to place a button at the end of the RecyclerView. When the recycler is empty, the button should expand to all available space. When items are added to the recycler, the button should squeeze down to a minimum.
There are some new additions to ConstraintLayout 1.1.0, like layout_constraintWidth_min, but I don't get it working. Is it supposed to work the way I intend?
Here are the relevant attributes, not including height:
<android.support.v7.widget.RecyclerView
android:id="#+id/horizontal_recycler"
android:layout_width="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#+id/add">
</android.support.v7.widget.RecyclerView>
and
<Button
android:id="#+id/add"
android:layout_width="0dp"
app:layout_constraintWidth_min="80dp"
app:layout_constraintStart_toEndOf="#+id/horizontal_recycler"
app:layout_constraintEnd_toEndOf="parent">
</Button>
So here is my solution.
<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">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_marginEnd="80dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/button"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="ADD"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/recyclerView"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Please note that in order to keep the recyclerView from squishing the button the margin end on the recycler should equal the button with plus any padding and margin you see fit to have.

Categories

Resources