Android: Show toolbar when scrolling UP(Drag UP) and hide when scrolling down(Drag down) - android

I have a scenario where the Toolbar/Action Bar, in an Activity, has an opposite behaviour than the general Toolbar behaviour. It should hide when the motion layout inside a fragment is scrolled UP and show when the motion layout is scrolled DOWN, which is the opposite of the general scroll behaviour.
I trie hiding the Support Action Bar and the toolbar layout completely but it is without any animation and does not bode well, since the Activity contains a BottomNavigation View, so the constant hiding and showing of Action bar does not look good.
supportActionBar?.hide()
containerToolbar.visibility = View.GONE
The AppBarLayout.LayoutParams scroll-flags apparently add the general behaviour.
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
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"
app:layoutDescription="#xml/collapsing_header_arc"
app:showPaths="false"
android:background="#color/white"
tools:showPaths="true">
<com.github.florent37.shapeofview.shapes.ArcView
android:id="#+id/header"
android:layout_width="0dp"
android:layout_height="200dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shape_arc_height="26dp"
android:background="#color/yellow_dark"
app:shape_arc_position="bottom">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_actionbar_gradient" />
<ScrollView
android:id="#+id/scrollview_counts_container2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/counts_container"
layout="#layout/layout_card_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</ScrollView>
</com.github.florent37.shapeofview.shapes.ArcView>
<View
android:id="#+id/guideline_anchor"
android:layout_width="wrap_content"
android:layout_height="5dp"
android:orientation="horizontal"
android:background="#color/red_dark"
app:layout_constraintTop_toBottomOf="#id/header"/>
<View
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="210dp"
app:layout_constraintBottom_toBottomOf="#+id/guideline_anchor"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/guideline_anchor"
android:background="#color/btnRedAlpha" />
<androidx.core.widget.NestedScrollView
android:id="#+id/parent_parent_dashboard"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/recyclerView"
android:background="#color/transparent"
android:layout_marginTop="#dimen/marginNormal">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/parent_dashboard"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ScrollView
android:id="#+id/scrollview_counts_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#+id/calendar_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="0.0"
android:nestedScrollingEnabled="true"
android:visibility="gone">
<include
android:id="#+id/counts_container"
layout="#layout/layout_card_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"/>
</ScrollView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="#dimen/marginBig"
app:layout_constraintTop_toBottomOf="#id/scrollview_counts_container"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.0">
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#color/yellow_dark" />
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_marginTop="#dimen/marginBig"
android:background="#color/yellow_dark"/>
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_marginTop="#dimen/marginBig"
android:background="#color/yellow_dark"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<!--<androidx.appcompat.widget.AppCompatTextView-->
<!--android:id="#+id/headerText"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_gravity="center_vertical"-->
<!--android:layout_marginLeft="23sp"-->
<!--android:elevation="4dp"-->
<!--android:gravity="center_vertical|left"-->
<!--android:text="I love paris"-->
<!--android:shadowColor="#3E3E3E"-->
<!--android:shadowDx="2"-->
<!--android:shadowDy="2"-->
<!--android:shadowRadius="4"-->
<!--android:textColor="#android:color/holo_blue_dark"/>-->
</androidx.constraintlayout.motion.widget.MotionLayout>
collapsing_header_arc.xml
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="#id/end"
app:constraintSetStart="#id/start">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="#id/guideline_anchor"
app:touchAnchorSide="top" />
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#id/header"
android:layout_height="240dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="arcHeightDp"
app:customFloatValue="60" />
</Constraint>
<Constraint
android:id="#id/scrollview_counts_container2">
<CustomAttribute
app:attributeName="visibility"
app:customStringValue="visible" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#id/header"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="arcHeightDp"
app:customFloatValue="0" />
</Constraint>
<Constraint
android:id="#id/scrollview_counts_container2">
<CustomAttribute
app:attributeName="visibility"
app:customStringValue="gone" />
</Constraint>
</ConstraintSet>
</MotionScene>
Is there a way to implement this?

You can try to make collapse toolbar and manage it as you want. If you have problems to manage activity toolbar from the fragment you could use callback / or events / or observables to call activity animation when something happens from fragment. So for example you have a view in Activity with animation method something like here Show and hide a View with a slide up/down animation and just call it from the fragment.

Related

MotionLayout progress jumps from 0 to 1 without intermediate steps

I have a MotionLayout with a TransitionListener and progress seems to go from 0 to 1 for my MotionScene:
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<Transition
app:constraintSetStart="#id/header_expanded"
app:constraintSetEnd="#id/header_condensed"
app:duration="2000">
<OnSwipe
app:touchAnchorId="#id/view_pager"
app:dragDirection="dragDown"
app:touchAnchorSide="top"/>
<KeyFrameSet>
<KeyAttribute
android:elevation="#dimen/header_elevation_expanded"
app:framePosition="0"
app:target="#id/header"/>
<KeyAttribute
android:elevation="#dimen/header_elevation_expanded"
app:framePosition="90"
app:target="#id/header"/>
<KeyAttribute
android:elevation="#dimen/header_elevation_collapsed"
app:framePosition="100"
app:target="#id/header" />
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="#+id/header_expanded">
<Constraint
android:id="#+id/guideline_expanded_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
</ConstraintSet>
<ConstraintSet android:id="#+id/header_condensed">
<Constraint
android:id="#+id/guideline_expanded_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.18" />
</ConstraintSet>
</MotionScene>
If print the progress in the log it seems to jump from 0 to 1. I have tried changing the duration, or just changing the constraints for the header view to a different guideline but it doesn't seemt o affect the progress.
The only weird thing that I see in the logs is the fact that it cannot find the OnSwipe touchAnchorId view.
W/MotionLayout: WARNING could not find view id com.pitchero.ph:id/view_pager
The layout using this MotionScence is below:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout android:id="#+id/container"
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/activity_background"
app:layoutDescription="#xml/motion_scene_team">
<com.github.florent37.shapeofview.shapes.DiagonalView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="0dp"
android:elevation="#dimen/menu_header_elevation_expanded"
app:layout_constraintBottom_toTopOf="#+id/guideline_expanded_state"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shape_diagonal_angle="#dimen/header_angle"
app:shape_diagonal_direction="left"
app:shape_diagonal_position="bottom">
<View
android:id="#+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/redE64"/>
</com.github.florent37.shapeofview.shapes.DiagonalView>
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/transparent"
app:layout_collapseMode="pin">
<LinearLayout
android:id="#+id/toolbar_title_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:elevation="5dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="#+id/toolbar_image"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="7dp"
android:visibility="gone"/>
<TextView
android:id="#+id/title"
style="#style/title.white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="true"
android:maxLines="1"
tools:text="Help Center"/>
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabs_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#color/transparent"
android:elevation="2dp"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar"
app:tabBackground="#color/transparent"
app:tabIndicatorColor="#color/white"
app:tabSelectedTextColor="#color/white"
app:tabTextColor="#color/white_50_percent"/>
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tabs_bar"/>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline_expanded_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
I don't really understand why this is happening in this particular case. I suspect it's because it cannot find the ViewPager but I don't see why that would happen.
Also, I'm using the following version of the ConstraintLayout libs:
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
implementation 'androidx.constraintlayout:constraintlayout-solver:2.0.0-alpha3'
Any help would be much appreciated, thank you!
You have implemented MotionLayout in a wrong way, first of all, you must not use Guideline to set animation, You can use ViewGroup containers or View for Animation.
Next thing, you must define all ContraintSet which are referencing another layout.
For ex.
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tabs_bar"/>
Here you are using app:layout_constraintTop_toBottomOf="#id/tabs_bar" as a reference, so if you are animating That viewpager, you will need to add ConstraintSet for both of them, Then only you can get rid of that warning. :)

MotionLayout with vertical ScrollView

I'm trying to make animation with motion layout, and want to set scrollView as targetAnchor for motion scene onSwipe Transition, but it doesn't work.
Maybe I don't know some thing about onSwipe transition.
Here is my layout file
<androidx.constraintlayout.motion.widget.MotionLayout 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:background="#color/main_background_color"
app:layoutDescription="#xml/base_scroll_scene">
<ImageView
android:id="#+id/background_image"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="#dimen/scrollable_background_image_margin_bottom"
android:scaleType="centerCrop"
android:src="#drawable/lift_bg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="#dimen/top_gradient_mask_height"
android:background="#drawable/top_gradient_mask"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/ski_more_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/ski_more_logo_margin_top"
android:src="#drawable/ic_skimore_logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/locked_icon"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="#dimen/locked_icon_margin_top"
android:src="#drawable/ic_lock"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/ski_more_logo" />
<FrameLayout
android:id="#+id/bottom_gradient_mask"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#drawable/bottom_gradient_mask"
app:layout_constraintBottom_toBottomOf="#+id/background_image" />
<ScrollView
android:id="#+id/content_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:overScrollMode="never"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:id="#+id/content_container_view"
android:layout_width="match_parent"
android:clickable="false"
android:layout_height="match_parent" />
</ScrollView>
</androidx.constraintlayout.motion.widget.MotionLayout>
In scroll view programmatically i'm adding some content with big height, which will be scrollable.
And here is my motion scene
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="#+id/end"
motion:constraintSetStart="#+id/start"
motion:duration="1000">
<OnSwipe
motion:dragDirection="dragUp"
motion:touchAnchorId="#+id/content_scroll_view"
motion:touchAnchorSide="top" />
</Transition>
<ConstraintSet android:id="#+id/start"/>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#+id/background_image"
android:layout_width="0dp"
android:layout_height="#dimen/top_gradient_mask_height"
android:layout_marginBottom="#dimen/scrollable_background_image_margin_bottom"
android:scaleType="centerCrop"
android:src="#drawable/lift_bg"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</MotionScene>
Please help me, Thanks.

Motion layout prevents update on recyclerview

I have started using motion layout for some top bar scrolling, and looks like there is an issue that prevents recycler view from showing updated data. Currently I am using 2.0.0-alpha3 of ConstraintLayout. In the view I have toolbar and 2 tabs that act as filter, lets say filterX and filterY those pass some rx stuff that basically just filters list of items based on the type this is not important because data is filtered properly, thread is correct, data is passed to adapter every time, but when I do scroll my motion layout to top or bottom, from time to time the changes are not reflected in recycler view, they reload after I scroll it a little bit or even touch, its not happening in case of standard ConstraitLayout. Have anyone experienced this and know any solution?
Edit: Layout with motion layout:
<androidx.constraintlayout.motion.widget.MotionLayout 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"
app:layoutDescription="#xml/scene_month">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="#drawable/ic_back"/>
<TextView
android:id="#+id/title"
style="#style/ActivityTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar" />
<com.example.FilterView
android:id='#+id/filter_view'
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/title"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:paddingBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/filter_view" />
</androidx.constraintlayout.motion.widget.MotionLayout>
And motion scene
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="#id/end"
app:constraintSetStart="#id/start">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="#id/recycler"
app:touchAnchorSide="top" />
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint android:id="#id/title"
android:text="#string/title"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:textSize="28sp"
android:textColor="#color/dark_gray"
android:fontFamily="#font/rubik_medium"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="28"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint android:id="#id/title"
android:text="#string/title"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:gravity="center_vertical"
android:minHeight="?actionBarSize"
android:textSize="28sp"
android:textColor="#color/dark_gray"
android:fontFamily="#font/rubik_regular"
android:layout_marginStart="72dp"
android:layout_marginEnd="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="textSize"
app:customFloatValue="20"/>
</Constraint>
</ConstraintSet>
</MotionScene>

MotionLayout OnSwipe transition gets triggered by wrong anchor

So we're trying to mimic the behaviour of a peek-able BottomSheetLayout (a bottom View peeking out from the bottom of the screen, which comes into full-screen view when scrolling it upwards, sort of like this: https://www.youtube.com/watch?v=yrZVLL-z6P4) using MotionLayout, version 2.0.0-alpha4.
The problem is that the OnSwipe transition on the peek-able view doesn't apply to the View itself, it apparently applies to the entire view underneath, in this case a RecyclerView. So when we scroll the RecyclerView, the transition is being run.
root_view.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.motion.widget.MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/motion_scene">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipToPadding="false"
android:paddingBottom="#dimen/margin_48"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/btn"
android:layout_width="match_parent"
android:layout_height="#dimen/size_48"
android:elevation="#dimen/elevation_12"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="#dimen/elevation_12"
android:rotation="90"
app:layout_constraintBottom_toBottomOf="#id/btn"
app:layout_constraintEnd_toEndOf="#id/btn"
app:layout_constraintTop_toTopOf="#id/btn" />
<FrameLayout
android:id="#+id/fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="#dimen/elevation_8"
app:layout_constraintTop_toBottomOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</FrameLayout>
motion_scene.xml
<Transition
android:id="#+id/swipe"
app:constraintSetEnd="#id/end"
app:constraintSetStart="#id/start"
app:duration="250">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="#id/btn" />
</Transition>
<ConstraintSet android:id="#+id/start">
<Constraint
android:id="#id/fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="parent" />
<Constraint
android:id="#id/btn"
android:layout_width="match_parent"
android:layout_height="#dimen/size_48"
app:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="#+id/end">
<Constraint
android:id="#id/fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/btn" />
<Constraint
android:id="#id/btn"
android:layout_width="match_parent"
android:layout_height="#dimen/size_48"
app:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>

How can make the RecyclerView fill out the free space when I use ConstraintLayout?

I'm a beginner of ConstraintLayout of Android Studio 3.2.1, it seems that ConstraintLayout is hard to operate.
I hope that the four button located the bottom of screen, and RecyclerView control fill out all free space of the screen, but the following code doesn't do it as my expectation, you can see the following Image.
How can I fix it?
BTW, the modified Code can't work well too.
Modified Code
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
Layout Code
<?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">
<ImageButton
android:id="#+id/btnOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/delete32"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/btnAddEdit" />
<ImageButton
android:id="#+id/btnAddEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/delete32"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/btnOne"
app:layout_constraintRight_toLeftOf="#+id/btnThree" />
<ImageButton
android:id="#+id/btnThree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/delete32"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/btnAddEdit"
app:layout_constraintRight_toLeftOf="#+id/btnFour" />
<ImageButton
android:id="#+id/btnFour"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/delete32"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/btnThree"
app:layout_constraintRight_toRightOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="#+id/btnOne"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.ConstraintLayout>
Image
You have to align the RecyclerView to top of parent layout and have to set the "android:layout_height " of recyclerview to 0dp.
I modified your layout code and it is working fine. Copy it and compare your with this.
<?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">
<ImageButton
android:id="#+id/btnOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/btnAddEdit"
app:srcCompat="#drawable/delete32" />
<ImageButton
android:id="#+id/btnAddEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/btnOne"
app:layout_constraintRight_toLeftOf="#+id/btnThree"
app:srcCompat="#drawable/delete32" />
<ImageButton
android:id="#+id/btnThree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/btnAddEdit"
app:layout_constraintRight_toLeftOf="#+id/btnFour"
app:srcCompat="#drawable/delete32" />
<ImageButton
android:id="#+id/btnFour"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/btnThree"
app:layout_constraintRight_toRightOf="parent"
app:srcCompat="#drawable/delete32" />
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/btnAddEdit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
You could try this:
<android.support.v7.widget.RecyclerView
android:id="#+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/btnOne"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Resources