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.
I have to hide Particular views in recyclerview, I am trying to hide some views but view has gone but space is there,I have tried putting heights=0 in cardview but still did not work , what I should I do?
This is my XML code list data
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-
auto">
<android.support.v7.widget.CardView
android:id="#+id/child_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2sp"
app:cardElevation="12sp"
android:visibility="gone">
<LinearLayout
android:id="#+id/main_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:orientation="vertical"
android:padding="3dp"
android:visibility="visible">
<ImageView
android:id="#+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="#drawable/bsp_icon" />
<android.support.v7.widget.AppCompatTextView
android:id="#+id/label_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:lines="2"
android:maxLines="2"
android:padding="0dp"
android:textColor="#color/Black" />
</LinearLayout>
</android.support.v7.widget.CardView>
</layout>
and this is my recyclerview
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="0dp"
tools:listitem="#layout/list_layout_dashboard_child_view">
</android.support.v7.widget.RecyclerView>
this is my Adapter code
if (txnTypeMap.get("CUST_CR") != null &&
obj.getChildName().equalsIgnoreCase(txnTypeMap.get("CUST_CR"))) {
binding.childCardView.setVisibility(View.VISIBLE);
}
important always set this if you are sure your data will change in recyclerview mRecyclerView.setHasFixedSize(false);
first remove the item from list e.g. list.remove(position which you want to hide)
next call notifyItemChanged(postion) and it should work ->this is better approach than calling notifyDataSetChanged()
You should hide all views or parent from UsersViewholder layout xml. You should hide entire viewholder or each view
Entire viewholder:
itemView.setVisibility(View.GONE);
or each element:
view.setVisibility(View.GONE);
But don't forget to set them VISIBLE otherwise, you will end up with some strange things from recycling
Without setting setVisibility to View.GONE, try to remove the the data from the data source and call notifyDataSetChanged()
This is the more efficient way to hide a view from RecyclerView
you have to set visibility gone to view in else case because views are reused in recycler view
if (txnTypeMap.get("CUST_CR") != null &&
obj.getChildName().equalsIgnoreCase(txnTypeMap.get("CUST_CR"))) {
binding.childCardView.setVisibility(View.VISIBLE);
} else binding.childCardView.setVisibility(View.GONE);
I hope it will work.
this is my XML layout with name songlist :
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/viewA"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:background="#android:color/holo_purple"
android:orientation="horizontal"/>
<android.support.v4.widget.NestedScrollView
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/holo_blue_bright"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="308dp"
/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:src="#drawable/personlog"
app:layout_anchor="#id/viewA"
app:layout_anchorGravity="bottom|center"/>
</android.support.design.widget.CoordinatorLayout>
and this is my fragment which contain this layout :
public class SongList extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.songlist,container,false);
textView=(TextView)view.findViewById(R.id.txt);
View bottomSheet = view.findViewById(R.id.bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setPeekHeight(200);
return view;}
}
but when lunch the app give me this error :
java.lang.IllegalArgumentException: The view is not a child of CoordinatorLayout
from this line :
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
how can fix this ? seems all things work fine but give that error ... if any one can please help
The BottomSheetBehavior is
An interaction behavior plugin for a child view of CoordinatorLayout to make it work as a bottom sheet.
At the moment you bottom sheet NestedScrollView is a child of LinearLayout. So just drop the outer-most LinearLayout all completely.
<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">
<LinearLayout
android:id="#+id/viewA"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:background="#android:color/holo_purple"
android:orientation="horizontal"/>
<android.support.v4.widget.NestedScrollView
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/holo_blue_bright"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="308dp" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:src="#drawable/personlog"
app:layout_anchor="#id/viewA"
app:layout_anchorGravity="bottom|center" />
</android.support.design.widget.CoordinatorLayout>
But now you have some more issues with the bottom sheet you're trying to implement. Firstly you should not use wrap_content with a scroll view. Secondly you should not use a list view inside a scroll view, since it's implementing its own scrolling. You might be able to simplify this by only using the list view as a bottom sheet.
If you are using data binding and including the layout to the fragment you have to do like following
val sheetBehavior = BottomSheetBehavior.from(binding.layoutBottomSheet.root)
Note, if you don't use a CoordinatorLayout and instead use the BottomSheetDialogFragment (which makes one for you), I noticed that you cannot navigate to that dialog fragment with Fragment directions using the current version of the Nav component library (2.1.0-alpha05) and must instantiate it as a new fragment dialog otherwise you get this error, i.e. instead of using this:
navController().navigate(MerchantHistoryFragmentDirections.showDateSelection())
You must use this:
fragmentManager?.let {
val dateSelection = DateSelectionFragment.newInstance()
dateSelection.setTargetFragment(this, RC_DATE_SELECTION)
dateSelection.show(it)
}
It's a kind of obtuse error so hopefully this helps someone.
In my case I have used the following solution to solve the issue
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.setOnShowListener { dialogInterface ->
val bottomSheetDialog = dialogInterface as BottomSheetDialog
setupFullHeight(bottomSheetDialog)
}
return dialog
}
val bottomSheet = bottomSheetDialog
.findViewById<FrameLayout>(R.id.design_bottom_sheet)
val behavior: BottomSheetBehavior<*>?
if (bottomSheet != null) {
behavior = BottomSheetBehavior.from(bottomSheet)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.isDraggable = false
}
In my case instead of
<?xml version="1.0" encoding="utf-8"?>
<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"
>
I used <android.support.constraint.ConstraintLayout (in a fragment or activity that contains a layout and a BottomSheet).
you have to set your bottom sheet layout in appbar layout below your content layout
you should change your layout design to
<androidx.coordinatorlayout.widget.CoordinatorLayout
it works for me
I'm trying to implement an empty view solution for a RecyclerView via data binding based on this solution. I have a RecyclerView and RelativeLayout (the empty view) within a SwipeRefreshLayout. Here is the XML for the layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="dataset"
type="...SeriesList"/>
</data>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/list"
android:name="...SeriesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="10dp"
app:layoutManager="LinearLayoutManager"
tools:context=".fragments.SeriesFragment"
android:visibility="#{dataset.size() > 0 ? View.VISIBLE : View.GONE}"/>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="#{dataset.size() > 0 ? View.GONE : View.VISIBLE}">
<TextView
android:id="#+id/empty_text"
style="#style/Base.TextAppearance.AppCompat.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/empty_image"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:width="300dp"
android:gravity="center"
android:textColor="#59000000" />
<ImageView
android:id="#+id/empty_image"
android:layout_width="128dp"
android:layout_height="160dp"
android:layout_centerInParent="true"
android:src="#drawable/empty" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</layout>
As you can see the RelativeLayout after the RecyclerView is the empty view, with their visbilities based on the size of the dataset, which is a SeriesList (extends ObservableArrayList). In the fragment containing this layout I bind the data like so:
FragmentSeriesListBinding binding = FragmentSeriesListBinding.inflate(inflater);
binding.setDataset(getmAdapter().getVisibleSeries());
So based off of this, I'm assuming when the adapter's visible SeriesList is empty, the visibilities of the RecyclerView will be GONE and the empty view will be VISIBLE. Upon testing with an empty dataset both the RecyclerView (with no items) and the empty view have a visibility of VISIBLE, which shouldn't be possible. Could someone shed some light as to why this isn't working as I expect?
So I ended up fixing this after reading here that SwipeRefreshLayout must have one child, so I wrapped the RecyclerView and RelativeLayout in a FrameLayout. I also used this solution to inflate the Fragment's layout with the DataBindingUtil inflate() method and setting the binding in the Fragment's onCreateView() method.
How to use RecyclerView inside NestedScrollView?
RecyclerView content is not visible after setting adapter.
UPDATE layout code updated.
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/keyline_1">
</RelativeLayout>
<View
android:id="#+id/separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#e5e5e5" />
<android.support.v7.widget.RecyclerView
android:id="#+id/conversation"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Replace your recyclerView with,
<android.support.v7.widget.RecyclerView
android:id="#+id/conversation"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
here,
app:layout_behavior="#string/appbar_scrolling_view_behavior"
will manage the rest of things.
One more thing, no need to put your recyclerView inside NestedScrollView
You need to use support library 23.2.0 (or) above
and RecyclerView height will be wrap_content.
recyclerView.setNestedScrollingEnabled(false)
But by doing this the recycler pattern doesn't work. (i.e all the views will be loaded at once because wrap_content needs the height of complete RecyclerView so it will draw all child Views at once. No view will be recycled). Try not to use this pattern unless it is really required. Try to use viewType and add all other views that need to scroll to RecyclerView rather than using RecyclerView in Scrollview. The performance impact will be very high.
To make it simple "it just acts as LinearLayout with all the child views"
UPDATE 1
Since Android Support Library 23.2.0 there were added method setAutoMeasureEnabled(true) for LayoutManagers. It makes RecyclerView to wrap it's content and works like a charm.
http://android-developers.blogspot.ru/2016/02/android-support-library-232.html
So just add something like this:
LayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setAutoMeasureEnabled(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setNestedScrollingEnabled(false);
UPDATE 2
Since 27.1.0 setAutoMeasureEnabled is deprecated, so you should provide custom implementation of LayoutManager with overridden method isAutoMeasureEnabled()
But after many cases of usage RecyclerView I strongly recommend not to use it in wrapping mode, cause this is not what it is intended for. Try to refactor whole your layout using normal single RecyclerView with several items' types. Or use approach with LinearLayout that I described below as last resort
Old answer (not recommended)
You can use RecyclerView inside NestedScrollView.
First of all you should implement your own custom LinearLayoutManager, it makes your RecyclerView to wrap its content.
For example:
public class WrappingLinearLayoutManager extends LinearLayoutManager
{
public WrappingLinearLayoutManager(Context context) {
super(context);
}
private int[] mMeasuredDimension = new int[2];
#Override
public boolean canScrollVertically() {
return false;
}
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
if (getOrientation() == HORIZONTAL) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
heightSpec,
mMeasuredDimension);
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
measureScrapChild(recycler, i,
widthSpec,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view.getVisibility() == View.GONE) {
measuredDimension[0] = 0;
measuredDimension[1] = 0;
return;
}
// For adding Item Decor Insets to view
super.measureChildWithMargins(view, 0, 0);
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(
widthSpec,
getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view),
p.height);
view.measure(childWidthSpec, childHeightSpec);
// Get decorated measurements
measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
After that use this LayoutManager for your RecyclerView
recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
But you also should call those two methods:
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
Here setNestedScrollingEnabled(false) disable scrolling for RecyclerView, so it doesn't intercept scrolling event from NestedScrollView. And setHasFixedSize(false) determine that changes in adapter content can change the size of the RecyclerView
Important note: This solution is little buggy in some cases and has problems with perfomance, so if you have a lot of items in your RecyclerView I'd recommend to use custom LinearLayout-based implementation of list view, create analogue of Adapter for it and make it behave like ListView or RecyclerView
You can use android:fillViewport="true" to make NestedScrollView measure the RecyclerView. The RecyclerView will fill the remaining height. so if you want to scroll the NestScrollView, you can set the RecyclerView's minHeight.
Simply adding recyclerView.setNestedScrollingEnabled(false); before setAdapter itself worked for me. I didn't add app:layout_behavior="#string/appbar_scrolling_view_behavior" anywhere & didn't set any custom layout manager
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#color/white"
android:text="Some Text..."
android:padding="15dp" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:padding="15dp"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Quick Links"
android:textColor="#color/black"
android:textStyle="bold"
android:textAllCaps="true"
android:paddingLeft="20dp"
android:drawableLeft="#drawable/ic_trending_up_black_24dp"
android:drawablePadding="10dp"
android:layout_marginBottom="10dp"
android:textSize="16sp"/>
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#efefef"/>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
This is what working for me
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.v4.widget.NestedScrollView>
For androidx it's called androidx.core.widget.NestedScrollView - and it scrolls alike butter with properties isScrollContainer and measureAllChildren enabled:
<!-- Scrolling Content -->
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="true"
android:measureAllChildren="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fastScrollEnabled="true"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical"
android:splitMotionEvents="false"
android:verticalScrollbarPosition="right"/>
</androidx.core.widget.NestedScrollView>
There is a simple and testing code u may check
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.NestedScrollView>
I used RecyclerView inside a NestedScrollView and it worked for me. The only gotcha I had to keep in mind was that a NestedScrollView takes only one child view. So in my case I used of LienearLayout viewgroup which was housing my RecyclerView plus a number of other views that I needed.
I experience one issue putting my RecyclerView inside the NestedScrollView. I realized that scrolling the content of my RecyclerView slacked.
I later realized that my RecyclerView was receiving the scrolling event and therefore was conflicting with the scrolling behavior of the NestedScrollView.
So to solve that problem, I had to disable the scroll functionality of my RecyclerView with this method movieListNewRecyclerView.setNestedScrollingEnabled(false);
You can checkout my Instagram for a short video of what I actually did. This is my instagram handle ofelix03
Try to use this library - https://github.com/serso/android-linear-layout-manager.
LayoutManager of the library makes RecyclerView wraps its contents. In this case RecyclerView will be "as big as inner views", so it will not have a scrollbars and user will use scrolling abilities of NestedScrollView. Therefore, it will not be ambiguous like "scrollable inside scrollable".
Here is the code that I'm using to avoid scrolling issues:
mRecyclerView = (RecyclerView) view.findViewById(android.R.id.list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.getLayoutManager().setAutoMeasureEnabled(true);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
I have Viewpager and RecyclerView inside the NestedScrollView. After adding below lines
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
I solved slow scroll and scroll lag issue.
if you want to use RecyclerView in NestedScrollView this is a simple tricky, just set :
RecyclerView
recyclerView.setHasFixedSize(false) (java/kt)
android:nestedScrollingEnabled="false"
android:layout_height="wrap_content"
android:overScrollMode="never"
NestedScrollView
android:fillViewport="true"
this is work for me, and you can use many RecyclerView in NestedScrollView with this too.
If you are using RecyclerView-23.2.1 or later. Following solution will work just fine:
In your layout add RecyclerView like this:
<android.support.v7.widget.RecyclerView
android:id="#+id/review_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />
And in your java file:
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager=new LinearLayoutManager(getContext());
layoutManager.setAutoMeasureEnabled(true);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(new YourListAdapter(getContext()));
Here layoutManager.setAutoMeasureEnabled(true); will do the trick.
Check out this issue and this developer blog for more information.
If you are using RecyclerView ScrollListener inside NestedScrollView, addOnScrollListener listener not working properly if you are used both.
Use this code.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
......
}
});
this code working fine RecyclerView ScrollListener inside NestedScrollView.
thanks
There are a lot of good answers. The key is that you must set nestedScrollingEnabled to false. As mentioned above you can do it in java code:
mRecyclerView.setNestedScrollingEnabled(false);
But also you have an opportunity to set the same property in xml code (android:nestedScrollingEnabled="false"):
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:nestedScrollingEnabled="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
You can't use a recycler view within a nested scroll view. It's not intended to contain further scrollable views but it's because it's a child of a scrolling layout itself that you need the nested scrolling view. I had the same issue but in the end I moved my textview to be a headerview within the recyclerview, made the recyclerview a direct child of the coordinator layout and deleted the nested scroll view. Then all my problems were gone.
One solution to keep the recycling feature of the recyclerview and avoiding the recyclerview to load all your data is setting a fix height in the recyclerview itself. By doing this the recyclerview is limited only to load as much as its height can show the user thus recycling its element if ever you scroll to the bottom/top.
do not use recyclerView inside NestedScrollView. it may cause cascading problems!
I suggest using ItemViewTypes in RecyclerView for handling multiple kinds of views.
just add a RecyclerView with match_parent width and height. then in your recyclerViewAdapter override getItemViewType and use position for handling what layout to be inflated. after that you can handle your view holder by using onBindViewHolder method.
https://stacklearn.ir
You can use my sample code
<?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">
<LinearLayout
android:id="#+id/fl_all_brand"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".view.fragment.AllBrandFragment">
<androidx.core.widget.NestedScrollView
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="#+id/fl_all_brand1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--<include layout="#layout/content_home" />-->
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/_15sdp"
android:layout_marginTop="#dimen/_20sdp"
android:fontFamily="#font/lexend_semibold"
android:text="#string/DISPLAY_LIGHTS"
android:textColor="#color/gray_scale_placehold"
android:textSize="#dimen/_16ssp" />
<LinearLayout
android:id="#+id/recyclerLayout"
android:layout_width="match_parent"
android:layout_height="#dimen/_280sdp">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerviewobj"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/_10sdp"
android:layout_marginTop="#dimen/_20sdp"
android:layout_marginEnd="#dimen/_10sdp"
android:orientation="horizontal"
android:nestedScrollingEnabled="false"
android:layout_marginBottom="#dimen/_20sdp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
/>
</LinearLayout>
<TextView
android:id="#+id/notfound"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/_15sdp"
android:layout_marginTop="#dimen/_20sdp"
android:layout_marginBottom="#dimen/_20sdp"
android:fontFamily="#font/lexend_semibold"
android:text="#string/DISPLAY_LIGHTS"
android:gravity="center"
android:visibility="gone"
android:textColor="?attr/hintTextColors"
android:textSize="#dimen/_12ssp" />
<TextView
android:id="#+id/recommendTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/addDeviceLayout"
android:layout_below="#+id/recyclerviewobj"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_7sdp"
android:fontFamily="#font/lexend_semibold"
android:text="#string/RECOMMENDATION"
android:textColor="#color/gray_scale_placehold"
android:textSize="#dimen/_16ssp" />
<LinearLayout
android:id="#+id/addDeviceLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/createRoomLayout"
android:layout_marginTop="#dimen/_14sdp"
android:background="?attr/buttonTextColor"
android:orientation="vertical"
tools:visibility="visible">
<ImageView
android:id="#+id/addBtn"
android:layout_width="#dimen/_28sdp"
android:layout_height="#dimen/_28sdp"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_8sdp"
android:src="#drawable/ic_thermostates_icon"
app:tint="?attr/colorPrimaryDark" />
<TextView
android:id="#+id/addDevice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_5sdp"
android:fontFamily="#font/lexend_bold"
android:text="#string/PROGRAM_DISPLAY_SENSOR_PLUGS"
android:textColor="?attr/colorPrimaryDark"
android:textSize="#dimen/_12ssp" />
<TextView
android:id="#+id/summry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_8sdp"
android:layout_marginBottom="#dimen/_6sdp"
android:fontFamily="#font/lexend_medium"
android:text="#string/DISPLAY_SENSOR_SUB_TITLE"
android:textColor="?attr/secondaryTextColor"
android:textSize="#dimen/_9ssp" />
<RelativeLayout
android:id="#+id/container3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_6sdp"
android:layout_marginTop="#dimen/_6sdp"
android:layout_marginBottom="#dimen/_10sdp">
<TextView
android:id="#+id/get_started"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="#dimen/_10sdp"
android:fontFamily="#font/lexend_semibold"
android:text="#string/RECOMMENDED_GROUP"
android:textAllCaps="true"
android:textSize="#dimen/_9ssp" />
<ImageView
android:id="#+id/forward_arrow"
android:layout_width="#dimen/_16sdp"
android:layout_height="#dimen/_16sdp"
android:layout_alignParentEnd="true"
android:layout_marginRight="#dimen/_20sdp"
android:src="#drawable/ic_forward_arrow"
app:tint="?attr/colorPrimary" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/createRoomLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginTop="#dimen/_9sdp"
android:layout_marginBottom="#dimen/_20sdp"
android:background="?attr/buttonTextColor"
android:orientation="vertical"
tools:visibility="visible">
<ImageView
android:id="#+id/addBtnRoom"
android:layout_width="#dimen/_28sdp"
android:layout_height="#dimen/_28sdp"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_8sdp"
android:src="#drawable/rgb_light_new"
app:tint="?attr/colorPrimaryDark" />
<TextView
android:id="#+id/addRooms"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_5sdp"
android:fontFamily="#font/lexend_bold"
android:text="#string/DISPLAY_RGBW"
android:textColor="?attr/colorPrimaryDark"
android:textSize="#dimen/_12ssp" />
<TextView
android:id="#+id/summry1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_16sdp"
android:layout_marginTop="#dimen/_8sdp"
android:layout_marginBottom="#dimen/_6sdp"
android:fontFamily="#font/lexend_medium"
android:text="#string/PROGRAM_DISPLAY_RGB_MSG"
android:textColor="?attr/secondaryTextColor"
android:textSize="#dimen/_9ssp" />
<RelativeLayout
android:id="#+id/container99"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/_6sdp"
android:layout_marginTop="#dimen/_6sdp"
android:layout_marginBottom="#dimen/_10sdp">
<TextView
android:id="#+id/get_started_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="#dimen/_10sdp"
android:fontFamily="#font/lexend_semibold"
android:text="#string/RECOMMENDED_GROUP"
android:textAllCaps="true"
android:textSize="#dimen/_9ssp" />
<ImageView
android:id="#+id/forward_arrow1"
android:layout_width="#dimen/_16sdp"
android:layout_height="#dimen/_16sdp"
android:layout_alignParentEnd="true"
android:layout_marginRight="#dimen/_20sdp"
android:src="#drawable/ic_forward_arrow"
app:tint="?attr/colorPrimary" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</layout>
here use this property of recyclerview
app:layout_behavior="#string/appbar_scrolling_view_behavior"
and turned off recyclerview nested scrolling like this
android:nestedScrollingEnabled="false"
I had to implement CoordinatorLayout with toolbar scrolling and it just took me all the day messing around this. I've got it working by removing NestedScrollView at all. So I'm just using RelativeLayout at the root.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_nearby"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</RelativeLayout>
nestedScrollView.setNestedScrollingEnabled(true);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//...
}
});
<androidx.core.widget.NestedScrollView
android:id="#+id/nested"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:layout_below="#id/appBarLayout_orders"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout ...
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
In my case, this is what works for me
Put android:fillViewport="true" inside NestedScrollView.
Make the height of RecyclerView to wrap_content, i.e android:layout_height="wrap_content"
Add this in RecyclerView android:nestedScrollingEnabled="false"
OR
Programmatically, in your Kotlin class
recyclerView.isNestedScrollingEnabled = false
mRecyclerView.setHasFixedSize(false)
For my case the child of NestedScrollview is ConstraintLayout. It is not working as expected i replaced it to LinearLayout. Maybe it helps someone.
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
I have used this awesome extension (written in kotlin but can be also used in Java)
https://github.com/Widgetlabs/expedition-nestedscrollview
Basically you get the NestedRecyclerView inside any package lets say utils in your project, then just create your recyclerview like
<com.your_package.utils.NestedRecyclerView
android:id="#+id/rv_test"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Check this awesome article by Marc Knaup
https://medium.com/widgetlabs-engineering/scrollable-nestedscrollviews-inside-recyclerview-ca65050d828a
At least as far back as Material Components 1.3.0-alpha03, it doesn't matter if the RecyclerView is nested (in something other than a ScrollView or NestedScrollView). Just put app:layout_behavior="#string/appbar_scrolling_view_behavior" on its top level parent that's a sibling of the AppBarLayout in the CoordinatorLayout.
This has been working for me when using a single Activity architecture with Jetpack Naviagation, where all Fragments are sharing the same AppBar from the Activity's layout. I make the FragmentContainer the direct child of the CoordinatorLayout that also contains the AppBarLayout, like below. The RecyclerViews in the various fragments are scrolling normally and the AppBar folds away and reappears as expected.
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:defaultNavHost="true"
app:navGraph="#navigation/mobile_navigation"/>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_scrollFlags="scroll|enterAlways|snap" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
liftOnScroll (used to for app bars to look like they have zero elevation when at the top of the page) works if each fragment passes the ID of its RecyclerView to AppBarLayout.liftOnScrollTargetViewId in Fragment.onResume. Or pass 0 if the Fragment doesn't scroll.
RecyclerView with NestedScrollView
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />