I am attempting to set up a layout with an "X" button pinned to the top of the screen, and then two elements centered in the view. One a recycler view and then, pinned below the recycler view, a button for form submission. The layout I currently have worked until the recycler view outgrows its bounds. Then the submission button is pushed below the bounds of the view and the recycler view does not stay within the layout. How can I center the two recycler and button views but not have the button go past view bounds if the recycler view grows large?
View With Small Recycler View Appears As (it should be centered. my example is slightly off.)
How View Should Appear with Larger Recycler View (the recycler view's content is too large to fit so it scrolls)
How View Actually Appears with Larger Recycler View (the recycler view does scroll, but now it pushes the button off the bottom of the view, which appears as the button being cut off)
Relevant Code Block for XML Layout
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.45"
android:orientation="vertical"
android:background="#color/backgroundLightSecondary"
android:padding="20dp" >
<Button
android:id="#+id/bt_close"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="end"
android:background="#drawable/ic_close"
android:textColor="#color/textLightPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:layout_weight="1"
android:gravity="center_vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_item_options"
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_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<Button
android:id="#+id/bt_order"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_weight="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="#drawable/bt_rounded_corner"
android:fontFamily="#font/microbrew_two"
android:padding="3dp"
android:text="#string/btn_add_to_order"
android:textColor="#color/backgroundLightSecondary"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
In such cases, the best way is to use a ConstraintLayout as the container. As you mentioned in the question, you want to lay the RecyclerView at the center. So, it leads to binding its top and bottom to the buttons.
On the other hand, if we make a chain between the RecyclerView and submitButton with a vertical chain style of packed, the submitButton would stick to the bottom of RecyclerView (which height is wrap_content to be able to grow) and moves with its bottom until it reaches the bottom of the screen (because of app:layout_constraintBottom_toBottomOf="parent").
The key point is to set app:layout_constrainedHeight="true" for the RecyclerView leading to not overlap with the two buttons.
<?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:padding="8dp" >
<androidx.appcompat.widget.AppCompatImageButton
android:id="#+id/closeImageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_baseline_close_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="#id/submitButton"
app:layout_constraintTop_toBottomOf="#id/closeImageButton"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/recyclerView" />
</androidx.constraintlayout.widget.ConstraintLayout>
Visual Result:
As I understand You want a button on top followed by recyclerview and than a Submit button in the end.And if size of recyclerview grows Submit button should not change its place.
Try this I make a rough layout
<LinearLayout //This is root layout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycle"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
Output of code looks like this
You can do everything you want in just one hierarchy by using ConstraintLayout. As an example, I edited your XML code as below;
<?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">
<Button
android:id="#+id/bt_close"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#drawable/ic_close"
android:textColor="#android:color/white"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_item_options"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="30dp"
android:layout_marginBottom="10dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toTopOf="#+id/bt_order"
app:layout_constraintTop_toBottomOf="#+id/bt_close" />
<Button
android:id="#+id/bt_order"
android:layout_width="150dp"
android:layout_height="50dp"
android:background="#android:color/holo_blue_dark"
android:padding="3dp"
android:text="Button"
android:textColor="#android:color/white"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/rv_item_options" />
</androidx.constraintlayout.widget.ConstraintLayout>
Related
Is there a way, using ConstraintLayout to achieve the below, without setting an invisible View on the right side as well? (The right back arrow should be invisible, I've made it visible to make things easier to understand)
The middle view currently is as follows:
<RelativeLayout
android:id="#+id/cover_wrapper"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="#dimen/_10sdp"
android:onClick="#{(view) -> viewModel.onAutoPlayButtonClick()}"
app:layout_constraintStart_toEndOf="#id/back_button"
app:layout_constraintEnd_toStartOf="#id/dummy_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/buttons_wrapper"
app:layout_constraintDimensionRatio="3:4">
Besides simply setting a right margin calculated as button_width + button_margin_left + button_margin_right, is there a trick to not have the right View there and not use margins either?
Yes you can achieve that using ConstraintLayout and Guidelines without setting any invisible View
<?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/grey"
>
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
app:layout_constraintEnd_toStartOf="#+id/guideline2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="#color/green"
android:background="#color/white"
android:padding="10dp"
app:srcCompat="?attr/actionModeCloseDrawable" />
<View
android:layout_width="0dp"
android:layout_height="200dp"
app:layout_constraintStart_toStartOf="#+id/guideline2"
app:layout_constraintEnd_toEndOf="#id/guideline3"
app:layout_constraintTop_toTopOf="#id/imageView"
/>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".3" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".7" />
</androidx.constraintlayout.widget.ConstraintLayout>
Image view is hiding under the button what changes I can do so that the image view can be above the button view pager also have bottom padding so that button can properly accommodate. The image is showing on the other parts but not above the button.
<?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"
android:orientation="vertical"
tools:context=".McqActivity"
android:id="#+id/fragment"
>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:id="#+id/starFirst"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/ic_baseline_star_24"
/>
<com.google.android.material.button.MaterialButton
android:id="#+id/right"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/questions_view_frag"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
android:orientation="horizontal"
android:paddingBottom="20dp"
android:paddingTop="50dp"
>
</androidx.viewpager2.widget.ViewPager2>
</androidx.constraintlayout.widget.ConstraintLayout>
layout_constraintBottom_toBottomOf and other layout_constraint... won't work inside RelativeLayout, these are desired to work with ConstraintLayout as strict parent. if you want to align two Views next to/below/above inside RelativeLayoyut you have to use other attributes, e.g.
android:layout_below="#+id/starFirst"
android:layout_above="#+id/starFirst"
android:layout_toRightOf="#id/starFirst"
android:layout_toLeftOf="#id/starFirst"
note that every attr which starts with layout_ is desired to be read by strict parent, not by View which have such attrs set. every ViewGroup have own set of such
edit: turned out that this is an elevation case/issue (Z axis), so useful attributes are
android:translationZ="100dp"
android:elevation="100dp"
On the screen, I want to show RecyclerView which start from the top and at the end of the RecyclerView, there is a button.
When RecyclerView is not occupying the entire screen then the Button will sit just below the RecyclerView.
When RecylerView is scrollable then in this case button will sit on the bottom of the screen.
I tried this code. But the problem here, RecyclerView sits in the centre. In my case, it will always start from the top(after the action bar).
Following code I tried:
main 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="#b6d7a8" >
<LinearLayout
android:id="#+id/actionBarTermsAndCondition"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/dark_gray"
android:gravity="center_vertical"
android:minHeight="70dp"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingTop="10dp"
android:paddingEnd="16dp"
android:paddingBottom="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<ImageView
android:id="#+id/closeButton"
android:layout_width="#dimen/spacing_2x"
android:layout_height="#dimen/spacing_2x"
android:layout_gravity="center_vertical"
android:layout_marginEnd="#dimen/spacing_2_5x"
android:clickable="true"
android:contentDescription="#string/close"
android:foreground="?selectableItemBackground"
android:src="#drawable/cross"
android:visibility="invisible" />
<TextView
android:id="#+id/route"
style="#style/ScreenTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="Import Venue"
android:fontFamily="#font/roboto"
android:text="Import Venue"
android:textColor="#color/white"
tools:text="Something" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:name="DataManagementFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="LinearLayoutManager"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="#id/constraint_layout_cloud_access"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/actionBarTermsAndCondition"
app:layout_constraintVertical_chainStyle="packed"
tools:itemCount="3"
tools:listitem="#layout/fragment_data_management_list_row" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constraint_layout_cloud_access"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FEAB8C"
android:paddingStart="16dp"
android:paddingTop="10dp"
android:paddingBottom="21dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/list">
<TextView
android:id="#+id/text_cloud_access"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/roboto"
android:text="Cloud access"
android:textColor="#3C3C41"
android:textSize="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Cloud access" />
<TextView
android:id="#+id/text_import_venue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/roboto"
android:text="Import venue"
android:textColor="#3C3C41"
android:textSize="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/text_cloud_access"
tools:text="Import place" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
RecyclerView row 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:background="#fff2cc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="#dimen/spacing_3x"
android:paddingStart="#dimen/spacing_2x"
android:paddingBottom="#dimen/spacing_2_5x"
android:paddingTop="#dimen/spacing_2_5x"
android:orientation="horizontal"
tools:showIn="#layout/fragment_data_management">
<TextView
android:id="#+id/text_floor_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/roboto"
android:textAppearance="?attr/textAppearanceListItem"
android:textColor="#3C3C41"
android:textSize="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Preloaded" />
<TextView
android:id="#+id/text_venue_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/roboto"
android:textAppearance="?attr/textAppearanceListItem"
android:textColor="#636367"
android:textSize="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/text_floor_name"
tools:text="ABC" />
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="?android:attr/listChoiceIndicatorMultiple"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/imageView2"
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:srcCompat="?attr/dividerHorizontal" />
</androidx.constraintlayout.widget.ConstraintLayout>
Your RecyclerView is centering between two other layouts. Add
app:layout_constraintVertical_bias="0.0"
to the XML for the RecyclerView to move it to the top. You can look up how bias works in the ConstraintLayout documentation.
I think you can achieve what you want with a guideline. The steps would be the following:
Create an horizontal guideline that sits at the 90% of the screen, meaning that it will be really close to the bottom, on the 10% left is where your button will be when the recycler view becomes scrollable.
Set the bottom constraint of the recycler view to match the top of the guideline and the top of the recycler view to the top of the screen. This will cause that the recycler view appears on the half of your screen.
Set the vertical bias of your recycler view to 0.0, this will stick the recycler view to the top.
Set the top constraint of the button to match the bottom of the recycler view, this will cause that it will stick to the bottom of the recycler view, but since the recycler view (thanks to the guideline) will only grow to 90% of the screen, the button will sit at the bottom of the screen as you want.
It's important to add the following attribute to the recycler view:
app:layout_constrainedHeight="true"
The layout related to the button and recycler view should look something like:
<?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">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/guideline"
app:layout_constraintVertical_bias="0.0"
tools:itemCount="130"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button text"
app:layout_constraintTop_toBottomOf="#+id/list"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.9"/>
</androidx.constraintlayout.widget.ConstraintLayout>
With few items:
With many items:
After adding a ConstraintLayout inside a ScrollView, I noticed that the content remains stuck in the middle of the screen (both horizontally and vertically). I already tried add android:layout_gravity="top" to the main ConstraintLayout but that didn't work. Is there something else I can use to position the content at the top?
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/cl_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingStart="#dimen/activity_horizontal_margin"
android:paddingEnd="#dimen/activity_horizontal_margin">
<androidx.cardview.widget.CardView
android:id="#+id/cv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
app:cardUseCompatPadding="true"
app:contentPadding="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#+id/tv_disclaimer">
<LinearLayout
android:id="#+id/ll_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/iv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:importantForAccessibility="no"
android:paddingEnd="10dp" />
<TextView
android:id="#+id/tv_title"
style="#android:style/TextAppearance.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<TextView
android:id="#+id/tv_disclaimer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:gravity="center"
android:textColor="?android:attr/textColorPrimary"
app:layout_constraintTop_toBottomOf="#+id/cv_title"
app:layout_constraintBottom_toTopOf="#+id/cv_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="#android:style/TextAppearance.Medium" />
<androidx.cardview.widget.CardView
android:id="#+id/cv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardUseCompatPadding="true"
app:contentPadding="10dp"
app:layout_constraintTop_toBottomOf="#+id/tv_disclaimer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/cl_description"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/ll_allergies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#+id/ll_ingredients">
<ImageView
android:id="#+id/iv_allergies"
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="5dp"/>
<TextView
android:id="#+id/tv_allergies"
style="#android:style/TextAppearance.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
<LinearLayout
android:id="#+id/ll_allergyinfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="#+id/ll_allergies"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#+id/ll_ingredients">
<TextView
android:id="#+id/tv_allergyinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginBottom="2dp"
android:gravity="start"
style="#android:style/TextAppearance.Medium" />
</LinearLayout>
<LinearLayout
android:id="#+id/ll_ingredients"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="#+id/ll_allergyinfo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="#+id/iv_ingredients"
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="5dp" />
<TextView
android:id="#+id/tv_ingredients"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?android:attr/textColorPrimary"
style="#android:style/TextAppearance.Large" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
Current result
Two important things are going on here.
The first is that your ScrollView specifies android:fillViewport="true". This means that whenever the contents of the ScrollView are "smaller" than the screen size, they will be stretched to fill the screen. In other words, your wrap_content ConstraintLayout will only actually wrap its content when you have to scroll. In all other cases, your ConstraintLayout will functionally be match_parent in height.
The second is that the constraints on your CardView, TextView, and second CardView form a vertical chain. Chains have special behavior regarding spacing when the parent is larger than the sum of the views in the chain (which it is due to the fillViewport behavior discussed above); the default is "spread", which will position the three views such that all the remaining space is evenly divided into four chunks (one at the start of the chain, one between the first two views, one between the second two views, and the last at the end of the chain).
How to fix it, though?
The best thing to do is to break the chain. Assuming you just want the views all stacked one after the other, starting from the top of the screen, there's no need to use a chain. To break the chain, remove the bottom constraint from each view:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
...>
<androidx.constraintlayout.widget.ConstraintLayout
...>
<androidx.cardview.widget.CardView
android:id="#+id/cv_title"
...
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
...
</androidx.cardview.widget.CardView>
<TextView
android:id="#+id/tv_disclaimer"
...
app:layout_constraintTop_toBottomOf="#+id/cv_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.cardview.widget.CardView
android:id="#+id/cv_description"
...
app:layout_constraintTop_toBottomOf="#+id/tv_disclaimer"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
...
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
Alternatively, you could delete the fillViewport attribute from your ScrollView. Without this, the child ConstraintLayout won't ever be stretched to fill the screen, and wrap_content will mean that there's never any extra space to spread out between your chain views.
Try removing app:layout_constraintTop_toTopOf="parent" from your ll_allergies LinearLayout. When copied on my AS it was this line that was adding the unnecessary space between the textview and the layout. Alternatively, keep the constraint and add 0dp on its height so that it enforces the constraint.
UPDATE after comment: I think your views are overlapping because the bottom constraint of ll_allergies is on the top of ll_ingredients instead of ll_allergyinfo. Try changing this:
app:layout_constraintBottom_toTopOf="#id/ll_ingredients"
to this:
app:layout_constraintBottom_toTopOf="#id/ll_allergyinfo"
and bring back the wrap_content of ll_alergies. Hopefully, now everything will fall into place
Update: response no longer valide after the code was updated
There are some errors in your code:
1.you set the layout to be to bottom of itself
android:id="#+id/ll_ingredients"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="#+id/ll_ingredients"`
the id "ll_alighting" is not defined
I have a FrameLayout that consists of a list view and a button. The whole point of the FrameLayout is that elements that are after other elements will be displayed above them.
Since the button code is below the ListView code, I expected the button will always be on top, but it isn't. I can't figure it out - as soon as I get enough items in my list, the button is underneath it and it becomes obsolete.
XML:
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/lvMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#fff"
android:elevation="3dp"
android:paddingTop="8dp" />
<Button
android:id="#+id/btnAddMovie"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:background="#drawable/raised_action_button"
android:elevation="5dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="+"
android:textColor="#ffffff"
android:textSize="30sp" />
</FrameLayout>
From developer.android:
FrameLayout is designed to block out an area on the screen to display
a single item. Generally, FrameLayout should be used to hold a single
child view,
The current dimensions of the framelayout is the entire screen. If I was to use the entire screen for the above layout I would do something like the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:orientation="horizontal">
<ListView
android:id="#+id/lvMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#fff"
android:elevation="3dp"
android:paddingTop="8dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="#+id/btnAddMovie"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:background="#drawable/raised_action_button"
android:elevation="5dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="+"
android:textColor="#ffffff"
android:textSize="30sp" />
</LinearLayout>
</LinearLayout>
You can say 0dp weight for either a height or a width, but not both. You then team it up with a layout_weight. In this case the first nested linear layout takes up 5/6ths of the screen, the second 1/6th. Thus your button sits in a protected space that the list view will not block out.
The outer linear layout has a vertical orientation which makes the two inner layouts stack on top of each other, the inners are horizontal to make them go across the entire screen. You will need to tweak those weights to make it work for you.
You can use RelativeLayout for this. If you want button view over the listview android:layout_above="#+id/btnAddMovie" delete this line.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/lvMovies"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/btnAddMovie"
android:layout_marginBottom="8dp"
android:background="#fff"
android:elevation="3dp"
android:paddingTop="8dp" />
<Button
android:id="#+id/btnAddMovie"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:elevation="5dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="+"
android:textColor="#ffffff"
android:textSize="30sp" />
</RelativeLayout>
Remove the elevation property from the list view. That's it.
It seems like the elevation causes the element to be on top of other elements.