I'm trying to implement the following design on Android.
I know that to have the button at that position I should have two constraint layout; one for whole change password form and one for change password form without the Save button and then set the Save button's Top and Bottom constraint to the second ConstraintLayout.
But when I do this, the button goes behind the form, and therein lies the problem:
Here is my XML:
<android.support.design.widget.CoordinatorLayout 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=".ChangePasswordActivity">
<include
android:id="#+id/changePasswordBar"
layout="#layout/top_bar_full"></include>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.constraint.ConstraintLayout
android:id="#+id/changePasswordCTL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/activities_constraint_top_bottom"
android:layout_marginEnd="#dimen/activities_constraint_start_end"
android:layout_marginStart="#dimen/activities_constraint_start_end"
android:layout_marginTop="#dimen/activities_constraint_top_bottom"
android:background="#drawable/radius_background_exchange"
android:elevation="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
// some EditText and TextView views here
</android.support.constraint.ConstraintLayout>
<br.com.simplepass.loading_button_lib.customViews.CircularProgressButton
android:id="#+id/changePasswordBT"
style="#style/customButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="32dp"
android:layout_marginStart="32dp"
android:layout_marginTop="8dp"
android:fontFamily="#font/sans_web_medium"
android:text="#string/finish"
android:textAllCaps="false"
android:textColor="#android:color/white"
android:textSize="#dimen/signinup_button_font_size"
app:initialCornerAngle="5dp"
app:layout_constraintBottom_toBottomOf="#+id/changePasswordCTL"
app:layout_constraintEnd_toEndOf="#+id/changePasswordCTL"
app:layout_constraintStart_toStartOf="#+id/changePasswordCTL"
app:layout_constraintTop_toBottomOf="#+id/changePasswordCTL"
app:spinning_bar_color="#android:color/white"
app:spinning_bar_padding="6dp"
app:spinning_bar_width="4dp" />
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
When elevation isn't in the picture, views that are defined later in the XML file will draw "on top" of views defined earlier. However, your password form has android:elevation="5dp", and this will override the normal drawing order.
To fix, add elevation to the button as well. android:elevation="5dp" should be enough, since then they're at the same elevation and the normal rules should apply. But you could give it more elevation to guarantee that it always draws on top of the password form.
There is a 5dp elevation on the form and no elevation on the button, so it is partially obscured. Increase the button elevation to at least 5dp.
android:elevation="5dp"
You could achieve such design by using a CoordinatorLayout.
Example:
<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true">
<ImageView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="180dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:background="#color/primary" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_camera"
app:layout_anchor="#id/header"
app:layout_anchorGravity="bottom|center_horizontal" />
</android.support.design.widget.CoordinatorLayout>
just use the following to anchor the layout of your button to the layout of your library view:
app:layout_anchor= "id_of_password_form_layout"
Related
Here is my Persistent BottomSheet
<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:id="#+id/bs"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bottom_sheet_background"
android:elevation="2dp"
android:padding="#dimen/base_margin"
app:behavior_hideable="true"
app:behavior_peekHeight="#dimen/bottom_sheet_peek_height"
app:layout_behavior="#string/bottom_sheet_behavior">
When User scrolls RecycleView, BottomNavigation hides and I reduce height of BottomSheet accordingly in RecycleView's addOnScrollListener using:
binding.rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
//148 = 80(bottom navigation) + 56(bottom sheet)
if (dy < 0)//scroll down
bottomSheetBehavior.setPeekHeight(136, true);
else if (dy > 0)//scroll up
bottomSheetBehavior.setPeekHeight(56, true);
}
After BottomNavigation is hidden and BottomSheet height is reduced, if BottomSheet is clickable,
(either through code binding.bs.bs.setClickable(false); or through xml android:clickable="true")
I can't drag it to expand. If it is not clickable, click event goes through it and user click on RecycleView item underneath it.
Even when its height is not reduced and it isn't clickable then also click event goes under it and fire on RecycleView item.
I also tried setting nestedScrolling, which allowed expanding but after that start creating issues when collapsing. :(
UPDATE:
I noticed BottomSheet drag not works when I set Bottomsheet clickable and its peekheight < 80 dp, ie the height of BottomNavigation.
Reference:
Why am I able to click "behind" the bottomsheet in Android?
I had same use case of having a recycler view inside a bottom sheet and here's what my Bottom sheet XML looks like. Please try to check if this works for you!
Apart from this, I did not actually get it why you want to reduce the height of the bottom sheet, as Bottom sheet has the behavior of self adjusting its height respect to the content inside it.
Please if possible share your use case so that it will be easier for the community to answer which gonna hit the bonsai. Thanks!
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:background="#color/transparent"
android:layout_height="match_parent"
android:paddingTop="50dp"
android:id="#+id/rootLayout"
>
<include
android:id="#+id/progress"
layout="#layout/item_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/rootView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/bottom_sheet_rounded_background"
android:backgroundTint="#color/background_gray"
android:clipToPadding="true"
android:orientation="vertical"
app:layout_behavior="#string/bottom_sheet_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<RelativeLayout
android:id="#+id/title_rl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="24dp"
android:height="24sp"
android:fontFamily="#font/silka_bold"
android:text="#string/error_select_prescription"
android:textColor="#color/text_color_semi_black"
android:textSize="16sp" />
<ImageView
android:id="#+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp"
android:src="#drawable/ic_close_btn_gray" />
</RelativeLayout>
<View
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/btn_gray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/title_rl" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewPrescription"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingTop="#dimen/dimen_16dp"
tools:itemCount="10" />
</androidx.core.widget.NestedScrollView>
<include
android:id="#+id/btn_select_and_proceed"
layout="#layout/sticky_footer_design_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
val bottomSheet = dialog!!.findViewById<View>(R.id.design_bottom_sheet) as FrameLayout
val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from<View>(bottomSheet)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
These all are the states which you can use to manipulate the height or basically the behavior of the BottomSheet.
The structure of my layout file: Coordinator layout - NestedScrollView - Coordinator Layout - objects that i want to be able to scroll
My TextInputLayout with TextInputEditText is at the bottom of the screen and when filled, extends out of bounds of the screen. When I collapse the keyboard it’s still not scrollable.
Note: I don’t want to set maxLines to Edittext and make it scrollable itself. I want it to scroll with other elements.
However, if I put, for example, TextView at the bottom of the screen and it doesn’t fit, the page is scrollable. Any ideas?
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--other items i want to scroll-->
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/descriptionLayout"
android:layout_width="348dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="545dp"
android:ems="16"
android:fontFamily="#font/montserrat"
android:hint="Add image description (optional)"
android:inputType="textMultiLine|textAutoCorrect"
app:counterEnabled="true"
app:counterMaxLength="256"
app:boxBackgroundColor="#color/white"
app:srcCompat="#drawable/ic_round_cloud_upload_24"
android:textColor="#68B2A0"
android:textColorHint="#68B2A0"
app:hintTextColor="#68B2A0"
app:layout_anchor="#id/titleLayout"
app:boxStrokeErrorColor="#F75010"
app:boxStrokeColor="#68B2A0"
app:boxStrokeWidth="2dp"
app:errorIconTint="#color/error"
app:errorTextColor="#color/error"
app:layout_anchorGravity="center|bottom"
app:counterOverflowTextColor="#color/error"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:counterTextColor="#color/main_green"
>
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/descriptionTxt"
android:ems="16"
android:textSize="18sp"
android:textColor="#68B2A0"
android:fontFamily="#font/montserrat"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="7"
/>
</com.google.android.material.textfield.TextInputLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.core.widget.NestedScrollView>
<!--bottom app bar-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
This is because you hard set android:layout_marginTop="545dp". Try never to do that. Also i think use costaint layour in youre case is better. Just change <androidx.coordinatorlayout.widget.CoordinatorLayout> inside nested scroll view to <androidx.constraintlayout.widget.ConstraintLayout> and add this atributes:
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent
If you need to show nested view in fullscteen, just chaange android:layout_height="wrap_content" to android:layout_height="match_parent"
my floating action button shows up too low, even though it looks just fine in the Android Studio preview (see below).
FB is placed in root under CoordinatorLayout and set to show at the bottom end using android:layout_gravity.
This Layout is used in Fragment (extends Fragment) with Tabbed Activity using ViewPager. Android X.
Thanks
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragmentTableCoordinator"
tools:context=".fragment.FragmentTable">
<!-- CoordinatorLayout for Floating Button -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/fragmentTable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorBackgroundCards">
<!-- Total Card -->
<androidx.cardview.widget.CardView
android:id="#+id/card_viewNew"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp"
card_view:layout_constraintEnd_toEndOf="parent"
card_view:layout_constraintStart_toStartOf="parent"
card_view:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="fill_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/Total_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
card_view:layout_constraintGuide_percent="0.5" />
<!-- some textViews here -->
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<!-- RecyclerView with months -->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/Total_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:scrollbars="vertical"
android:visibility="visible"
card_view:layout_constraintEnd_toEndOf="parent"
card_view:layout_constraintStart_toStartOf="parent"
card_view:layout_constraintTop_toBottomOf="#+id/card_viewNew" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Floating button -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floating_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:contentDescription="TODO"
app:srcCompat="#android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
My own fix : after hours trying to fix in in Fragment Layout - the best for me worked :
place Floating button into activity_main layout
hide it (setVisibility) for Fragment you dont need.
This solved this for me
You're setting ConstraintLayout inside the CoordinatorLayout and also CoordinatorLayout in the Fragment layout. You'll need to change it a bit.
Use FloatingActionButton inside your main activity layout with CoordinatorLayout, AppBarLayout and maybe a NestedScrollView, use ConstraintLayout in your Fragment layout and then, as you already mentioned, you'll be able to see FloatingActionButton with desire effect which is also stable at the bottom of the page and then you can hide it in the Fragments you don't want to use.
I want to achieve the following behavior -
https://ezgif.com/optimize/ezgif-6-66c61806b01c.gif
here he is my XML file -
<?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:id="#+id/fragment_marketplace_root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="7dp">
<LinearLayout
android:id="#+id/fragment_marketplace_main_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:orientation="vertical">
<com.twoverte.views.ClearableAutoCompleteTextView
android:id="#+id/fragment_marketplace_searchview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="14dp"
android:completionThreshold="0"
android:hint="#string/fragment_marketplace_search_hint"
android:iconifiedByDefault="false"
android:inputType="text|textAutoCorrect"
android:maxLength="25"
android:textIsSelectable="false"
android:textSelectHandle="#xml/empty_shape"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="1dp" />
<TextView
android:id="#+id/fragment_marketplace_discover_products_from_myverte_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginTop="15dp"
android:fontFamily="#font/noto_sans"
android:text="#string/fragment_marketplace_discover_products_from_myverte"
android:textSize="17sp" />
<androidx.core.widget.NestedScrollView
android:id="#+id/fragment_marketplace_vendors_nested_scrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fragment_marketplace_vendors_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:orientation="horizontal"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/fragment_marketplace_vendor_row_item" />
</androidx.core.widget.NestedScrollView>
<androidx.core.widget.NestedScrollView
android:id="#+id/fragment_marketplace_featured_products_nested_scroll_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/fragment_marketplace_featured_products_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/very_light_grey"
android:fontFamily="#font/noto_sans"
android:paddingStart="14dp"
android:paddingLeft="14dp"
android:paddingTop="15dp"
android:paddingEnd="14dp"
android:text="#string/fragment_marketplace_featured_products"
android:textSize="17sp"
android:visibility="gone"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fragment_marketplace_products_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#color/very_light_grey"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:listitem="#layout/fragment_marketplace_products_row_item" />
<View
android:id="#+id/activity_product_page_bottom_view"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginTop="60dp"
android:background="#color/light_black"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I have tried SO MANY combinations with setOnScrollChangeListener and addOnScrollListener and nothing works as expected.
The needed result is to have the ability to increase and decrease the top RV up to a cap.
The decrease should be done when scrolling the bottom RV downwards while the increase is being done when scrolling up.
If someone can assist me with this I would literally kiss his legs, I have been investing so many hours trying to crack how to make this behavior that I am sick of it.
edit
the needed animation -
I finally figured it out. I will share the code for the XML file as it is first, then explain everything about it later.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:minHeight="132dp"
android:fitsSystemWindows="true"
app:titleEnabled="false"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<View
android:id="#+id/blue_view"
android:layout_width="match_parent"
android:layout_height="128dp"
android:background="#android:color/holo_blue_bright"
app:layout_collapseMode="pin"
app:layout_collapseParallaxMultiplier="0"
android:layout_gravity="top"/>
<HorizontalScrollView
android:id="#+id/pink_view"
android:layout_width="match_parent"
android:layout_height="128dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="1"
android:layout_gravity="bottom">
<View
android:layout_width="2000dp"
android:minWidth="2000dp"
android:layout_height="match_parent"
android:background="#color/colorAccent"/>
</HorizontalScrollView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note: I used View with different colors in order to preview different segments in the Layout. I also used HorizontalScrollView in order to showcase something like a RecyclerView as in the gif you uploaded.
Alright, so first, we need to create a CollapsingToolbarLayout with layout_scrollFlags.
we use scroll flag must be enabled for any scroll effects to take into effect
we use snap flag to determine what to do when a view only has been partially reduced. If scrolling ends and the view size has been reduced to less than 50% of its original, then this view to return to its original size. If the size is greater than 50% of its sized, it will disappear completely.
we use exitUntilCollapsed along with minHeight in order to collapse the Toolbar down to the specified minHeight
We want the CollapsingToolbarLayout to have:
layout_height set to the expanded height of the Toolbar
minHeight set to the collapsed height of the Toolbar
In this case, since we want the HorizontalScrollView (pink_view) only to get smaller in height, we set the minHeight to the [ height of blue_view + smaller height of pink_view ]
Therefore, since blue_view will remain 128dp and we want pink_view to go down to 4dp, we set the minHeight to 132dp.
So here is a small example. Assume the blue_view is like 100dp and the pink_view is initially 100dp. So that's how we want it to show at first, but when I start scrolling we want the pink_view to go down to 20dp and the blue_view will stay at 100dp.
Therefore, layout_height will be 200dp and the minHeight will be 120dp.
Now, we want the HorizontalScrollView or the pink_view to collapse with the CollapsingToolbarLayout height.
So, we add layout_collapseMode="parallax" to the pink_view such that it scrolls along with the CollapsingToolbarLayout.
The layout_collapseParallaxMultiplier determines what part of the image (in percent) will be hidden under the bottom content. And here, we want it all to be hidden. Therefore, we set it to 1.
Meanwhile, we want the blue_view to stay pinned to the top. And we also don't want it to be hidden under any bottom content.
So, we add layout_collapseMode="pin" to the blue_view such that it gets pinned to the top of the CollapsingToolbarLayout.
We also add layout_collapseParallaxMultiplier="0" in order to not have it be hidden under any content.
Please note that if the heights of the elements exceeds the minHeight, the CollapsingToolbarLayout will be pushed above the screen. It will then seem as if the height of the top item (here blue_view) is decreasing in size.
Preview:
Here is another demo with a RecyclerView:
The XML for the above RecyclerView demo is below if anyone is interested.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:minHeight="148dp"
android:fitsSystemWindows="true"
app:titleEnabled="false"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<View
android:layout_width="match_parent"
android:layout_height="128dp"
android:background="#android:color/holo_blue_bright"
app:layout_collapseMode="pin"
app:layout_collapseParallaxMultiplier="0"
android:layout_gravity="top"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/hv_list"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="128dp"
android:minHeight="20dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="1"
android:layout_gravity="bottom"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Edit : Important thing for RecyclerViews and ViewHolders
To achieve the height resize for RecyclerView and ViewHolder, we have to resize them when the offset of the AppBarLayout changes on scroll.
This is because the CollapsingToolbarLayout just scrolls the elements inside it under each other instead of actually resizing them.
So, we have to use the RecyclerView, called here hv_list, and the AppBarLayout, called here app_bar.
val hv_list: RecyclerView = findViewById(R.id.hv_list)
val app_bar: AppBarLayout = findViewById(R.id.app_bar)
After that, we need to remember the original size of the hv_list.
val hv_original_height: Int = hv_list.layoutParams.height
Finally, we need to set an OffsetChangedListener for the AppBarLayout. There, we will be changing the height of the RecyclerView and then give it a margin bottom to push it up only because it has a gravity bottom.
app_bar.addOnOffsetChangedListener(object : AppBarLayout.OnOffsetChangedListener {
override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int) {
hv_list.updateLayoutParams {
this.height = hv_original_height + i
(this as CollapsingToolbarLayout.LayoutParams).setMargins(0, 0, 0, abs(i))
}
}
})
Make sure that your itemView in the RecyclerView has height of match_parent
I try to use my own Toolbars in two Activities that have the ConstraintLayout.
In one Activity, I placed a button below the toolbar, what looks fine:
However, in the other Activity, I placed a ListView below the toolbar and suddenly there is a big gap between the Toolbar and the ListView:
I should note that this does not appear in the preview in AndroidStudio.
The layout of the Activities is exactly the same and in the Manifest, I set the application theme to NoActionBar.
I am happy about any kind of help :)
Here is some of the code of the "bad" Activity:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.nutritionanalyzer.RecipeOverviewActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/recipe_overview_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
android:visibility="visible"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark" />
<ListView
android:id="#+id/recipeOverviewListView"
android:layout_width="368dp"
android:layout_height="495dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/recipe_overview_toolbar" />
</android.support.constraint.ConstraintLayout>
Maybe the line
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
is guilty? But I have exactly the same line at the "good" Activity...
just set android:layout_height="0dp" in ListView because when you set width and height of a child in constraint layout to something other than zero and anchor edges of the child the view will be centered between anchor points because you have set these attributes (you have anchor view's top and bottom edges):
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#+id/recipe_overview_toolbar" />
I guess that you also want listView to match parent width if you want this just set android:layout_width="0dp" because you have these attributes in listView (you have anchor listView horizontally to parent):
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
and remove:
app:layout_constraintHorizontal_bias="1.0"