what I want to achive
A scrollView which expends the free vertical space only if needed and a button which is appended on bottom of that scrollView but not hidden by the footer when the amount of the items in the scroll view increases.
whats the problem
scrollView android:layout_height = wrap content:
the button stays at the bottom of the scrollView. But then, if the ScrollView extends, the button is hidden behind the footer.
scrollView android:layout_height = 0dp:
the button stays visible while the scrollView extends the screen height. But then the button position is fixed because the scrollView is not resizing according to the amount of items.
But I didn't find a way to meet both criterias.
question
how do I set the constraints of this Layout to get the expected behaviour (see first image below)?
design to achive
current 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="#style/Theme.AppCompat.Light">
<TextView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/shadeOfGrey2"
android:gravity="center"
android:text="header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/addItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/header"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_chainStyle="packed">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.core.widget.NestedScrollView>
<Button
android:id="#+id/addItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="button 01"
app:layout_constraintBottom_toTopOf="#id/footer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/nestedScrollView" />
<TextView
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/shadeOfGrey2"
android:gravity="center"
android:text="footer"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
current Android layout
I think I got it down to what you're expecting now. Could you verify?
<?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:theme="#style/Theme.AppCompat.Light">
<TextView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/shadeOfGrey2"
android:gravity="center"
android:text="header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="#+id/addItem"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/header"
app:layout_constraintVertical_bias="0"
app:layout_constraintVertical_chainStyle="packed">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:itemCount="8"
tools:listitem="#android:layout/simple_list_item_2" />
</androidx.core.widget.NestedScrollView>
<Button
android:id="#+id/addItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="button 01"
app:layout_constraintBottom_toTopOf="#+id/footer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/nestedScrollView"
app:layout_constraintVertical_bias="0" />
<TextView
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/shadeOfGrey2"
android:gravity="center"
android:text="footer"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Just keep in mind that your approach above won't be recycling any views in the RecyclerView adapter, so if the data is big then performance might become a concern.
Screenshots from Android Studio:
Related
I have a layout where the main content is scrollable. At the same time the confirm button is always visible at the bottom so no matter where you are scrolling you can always confirm and see the button.
Whenever I touch a EditText the ScrollView scrolls up so the keyboard does not hide the EditText. This is done using android:windowSoftInputMode="adjustResize".
The problem is, that the button always also scrolls up when I touch the EditText. I do not want this behaviour. I want the button to stay hidden behind the keyboard.
Here is the layout I use:
<?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:fitsSystemWindows="true"
tools:context=".SecondFragment">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:fillViewport="true"
app:layout_constraintBottom_toTopOf="#+id/button_second"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:hint="TYPE..."
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<Button
android:id="#+id/button_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="#string/previous"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
And here are two pictures demonstrating:
On the second picture, the Button also scrolls up. But I only want the keyboard below the EditText the button shall stay hidden at the bottom behind the keyboard (Like it would without adjustResize
EDIT:
As suggested with FrameLayout it works when I have no content that needs to scroll. But once I add another EditText like below it stops working again (I am also unfamiliar with FrameLayout, I always only use ConstraintLayout, So I assume somehow the ScrollView has to stay on top of the button anyway)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".SecondFragment">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
app:layout_constraintBottom_toTopOf="#+id/button_second"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/editText"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="300dp"
android:hint="TYPE..."
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:hint="TYPE..."
android:layout_marginTop="400dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/editText" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<Button
android:id="#+id/button_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_gravity="bottom|center"
android:text="#string/previous"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</FrameLayout>
Is this what you expected?
activity_main.xml
<FrameLayout 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">
<include
layout="#layout/layout_item"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:src="#android:drawable/ic_menu_add"
android:layout_gravity="bottom|right"
android:layout_marginBottom="16dp"
android:clickable="true" />
</FrameLayout>
layout_item.xml
<FrameLayout 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"
>
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="200dp"
android:hint="TYPE..." />
<Button
android:id="#+id/button_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="20dp"
android:text="previous"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</FrameLayout>
I'm trying to put a ConstraintLayout inside a NestedScrollView, but there is a line that separates the ConstraintLayout. I can't place anything underneath that invisible line. I have been trying for hours and can't find the issue.
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.core.widget.NestedScrollView
android:id="#+id/premium_layout_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BFFFFFFF"
android:focusableInTouchMode="true"
android:tag="layout/fragment_premium"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".PremiumFragment">
<ImageView
android:id="#+id/launcher_id"
android:layout_width="185dp"
android:layout_height="185dp"
android:layout_marginTop="25dp"
android:layout_marginBottom="20dp"
android:contentDescription="TODO"
app:layout_constraintBottom_toTopOf="#+id/premium_text_id"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/launch_premium" />
<TextView
android:id="#+id/premium_text_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="220dp"
android:text="#string/launch_to_premium"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView2"
android:layout_width="383dp"
android:layout_height="196dp"
android:layout_marginTop="24dp"
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/premium_text_id" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>
With a little bit of messing around I was able to get what you are looking for. The key is to use android:fillViewport="true" in the NestedScrollView
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.core.widget.NestedScrollView
android:id="#+id/premium_layout_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BFFFFFFF"
android:focusableInTouchMode="true"
android:fillViewport="true"
android:tag="layout/fragment_premium">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/launcher_id"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_marginTop="25dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/launch_premium" />
<TextView
android:id="#+id/premium_text_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/launch_to_premium"
android:textSize="24sp"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/launcher_id" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView2"
android:layout_width="383dp"
android:layout_height="196dp"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/premium_text_id" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>
You need to add a attribute android:fillViewport="true" in your NestedScrollView
<androidx.core.widget.NestedScrollView
android:id="#+id/premium_layout_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BFFFFFFF"
android:focusableInTouchMode="true"
android:fillViewport="true" <-- add this
android:tag="layout/fragment_premium">
why?
fillViewport allows NestedScrollView to extend its height equals to the full height of the device screen height in the cases when the child of scroll view has less height.
this blog Will explain more about it.
I have two linear layout inside constrainLayout,
The bottom linear layout includes buttons and its height is wrap_content and must be wrap, because sometimes I keep only 1 button and sometimes 2 buttons.
I would like to set height of the top linearLayout to max but without covering the 2nd layout.
So I decided to set match_parent to the first, but after that it covers the 2nd layout.
I can't use weight/weightsum
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="#+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2"
android:visibility="gone" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="11"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="9"
app:layout_constraintBottom_toTopOf="#+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
android:padding="16dp"
android:weightSum="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Button2"
" />
</LinearLayout>
try this added weight sum and weight to make layout in prportion
Since you are using ConstraintLayout, you can set the height of the first LinearLayout to 0dp. The ConstraintLayout interprets it as "match constraints".
The next step would be to properly define the constraints of the first LinearLayout (which you did).
You can read more about ConstraintLayout here.
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="#+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2"
android:visibility="gone" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
To do this you have to use a combination of linearlayout as parent and attribute layoutWeight ,If you use a constant value for layoutWeight for both top layout and button's container , then this will lead to some problem on different screen height devices , instead this solution make you able to set your buttons height as big as enough by setting its container's height to wrapContent and give all top area for the layout content .
You can also make the top linearLayout scrollable to get the best experience possible :
<?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:id="#+id/this_layout_will_fil_all_space_except_the_bottom_layout_space"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:background="#000000"
android:layout_weight="1">
</LinearLayout>
<LinearLayout
android:id="#+id/button_layout_at_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:padding="10dp">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
android:layout_marginEnd="50dp"/>
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
android:visibility="visible" />
</LinearLayout>
</LinearLayout>
For Buttons , you can set its width to wrapContent and add gravity attribute to its parent as above , in this way even if one buttons was gone , the other will fit perfectly in the center of the container .
Enjoy !
The main advantage of using ConstraintLayout is to avoid using any other nested ViewGroups, The more you add more hierarchy in layout, the less performance you'll have. You can check documentation for more.
So for performance wise it's better to add widgets/views directly within the ConstraintLayout.
So, here I removed the bottom LinearLayout, and kept only the buttons directly within the ConstraintLayout, you can do the same for the top LinearLayout, you can just add any underlying views directly to the ConstraintLayout
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="#+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</LinearLayout>
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="Button1"
app:layout_constraintBottom_toTopOf="#id/button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="Button2"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I am trying to make a Dialog that looks like this
Here, the elements in orange rectangles are fixed header and footer sections of the Dialog. The elements inside blue rectangle are placed dynamically depending on what content is to be shown.
Here it the XML for this.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/header_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- some views -->
</LinearLayout>
<LinearLayout
android:id="#+id/body_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="#id/header_section"
app:layout_constraintBottom_toTopOf="#id/footer_section"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/footer_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<!-- some views -->
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
It works fine when I place other views inside the blue area, but when a RecyclerView is placed inside it and items are dynamically added to it, it grows in size and overlaps the text in header section and pushes the footer section to bottom. How can I make the RecyclerView cover only the blue area?
Use height 0dp in body section so it will fit between header and footer
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/header_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- some views -->
</LinearLayout>
<LinearLayout
android:id="#+id/body_section"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="#id/header_section"
app:layout_constraintBottom_toTopOf="#id/footer_section"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
</LinearLayout>
<LinearLayout
android:id="#+id/footer_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<!-- some views -->
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
I use ScrollView to tackle this,
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ScrollView
android:id="#+id/scrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintHeight_min="100dp"
app:layout_constraintHeight_max="250dp"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingHorizontal="8dp"
android:paddingVertical="8dp"
/>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
The main attributes are these 3
app:layout_constraintHeight_min="100dp"
app:layout_constraintHeight_max="250dp"
app:layout_constrainedHeight="true"
I have a view constrained to bottom of the parent. I also have text fields on top. how ever when the keyboard shows up, it will push bottom views up which will cover my text fields.
I have everything inside a scroll view, keyboard should cover the bottom view and I should be able to scroll to bottom to reach the bottom view.
Here is a simple example. I manually increased the height to reproduce the problem easier. I actually have more views, this is just for demonstration.
note that fillViewPort is also enabled.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/edit_text_1"
android:layout_width="0dp"
android:layout_height="180dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<EditText
android:id="#+id/edit_text_2"
android:layout_width="0dp"
android:layout_height="180dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/edit_text_1" />
<View
android:id="#+id/bottom_view"
android:layout_width="0dp"
android:layout_height="160dp"
android:background="#color/grey_500"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
You just simply need to put the ScrollView inside a ConstraintLayout
like this:
<?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">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="0dp"
android:layout_height="180dp"
android:inputType="textPersonName"
android:ems="10"
android:id="#+id/edit_text_1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<EditText
android:layout_width="0dp"
android:layout_height="180dp"
android:inputType="textPersonName"
android:ems="10"
android:id="#+id/edit_text_2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/edit_text_1"/>
<View
android:layout_width="0dp"
android:layout_height="160dp"
android:id="#+id/bottom_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/edit_text_2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>