SwipeRefreshLayout does not work (animation not shown, onRefresh not called) when the first item in the RecyclerView within the SwipeRefreshLayout has a height of zero.
You can check out a test project on Github that shows this.
My question is: can this effect be circumvented?
In my actual project, due to circumstances not in my hand (Ad library)the first item of my list will sometimes have a height of 0, so setting it to View.GONE or height to 1 is not an option.
Found an workaround: Put RecyclerView to into additional view:
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
it cause additional overdraw, but works
few more suggestions found here: https://github.com/airbnb/epoxy/issues/74
If you can get a callback from the ad library you should be able to work around the bug by adding and removing the advertisement item from your RecyclerView.Adapter depending on whether or not the ad view has content to display.
Related
I have a horizontal Recyclerview with 2 elements
I would like to call a function to load into a data list when I scroll through the elements of the recyclerview.
I would like to load the data of the item located in the center of the screen / Recyclerview
I am trying with onScrolled but I cannot figure out when in the Recyclerview I change the item
the elements could perhaps become even more than 2 (for example 6) so if it were possible I would like a function that is not necessarily only for 2 elements
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list_compte"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
android:divider="#drawable/rectangle_border_bottom"
android:paddingLeft="110dp"
android:paddingRight="110dp"
android:clipToPadding="false"
android:dividerHeight="1dp"
android:isScrollContainer="false"
android:nestedScrollingEnabled="true"
android:orientation="horizontal" />
it's possible?
Thanks
Yes, it is possible. There is a good tutorial here by Nick Rout which perfectly describes your case.
I have a vertical recyclerview (with a GridLayoutManager) inside another recyclerview (with LinearLayoutManager). The problem I am facing right now is that, the inner recyclerview (with GridLayoutManager) binds all of it's items at the same time, even the views that are not on the screen at the moment (onBindViewHolder() gets called for all of its items).
To give you more information, in my layout file, I put height of my recycler view as wrap_content.
I think the problem is, since there are 2 nested vertically recyclerviews, when the parent RV wants to measure its children and the children is another RV, in onMeasure() it computes the size needed for the entire RV, not just the portion that it wants to bind on the screen.
Any idea how to solve this?
Here is the layout file for my outer recyclerview:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/component_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
And here is the code for my inner recyclerview:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/gutter"
android:paddingBottom="#dimen/gutter">
<TextView
android:id="#+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/gutter"
android:textSize="30sp"
android:textColor="#android:color/white"
android:fontFamily="sans-serif-thin"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
P.S.: I'm using this adapter delegate for my outer recyclerview:
https://github.com/sockeqwe/AdapterDelegates
I think nested recyclerviews are a very bad idea. When i try to scroll, which recyclerview has to respond the the scolling, the parrent or child.
That is why I think you are looking for the ExpandableListView? That's limited to only two levels of listings, but that sounds like it would work for your needs). It also solves the soling issue.
It would look something like this:
EDIT: even nested ExpandableListViews are possible:
EDIT: check this lib for horizontal scroling
This is a known bug.
You should not put a RecyclerView inside another RecyclerView because RecyclerView gives its children infinite space. Hence the inner RecyclerView keeps measuring till the dataset is exhausted. Try setting setAutoMeasureEnabled(false) to false on layout manager or you can solve this problem by using a wrapper adapter instead of inner recycler view.
The first thing you need to know is that, when you nest scrolling layouts, the inner ones will get infinity allowed height, effectively making them wrap_content. There is in fact a relatively easy way to fix this problem.
Say I had two nested RecyclerViews such as these, in this case vertically oriented.
<RecyclerView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical>
<View .../>
<!-- other stuff -->
<RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
</RecyclerView>
The inner recyclerView here will bind all of it's children immediately every time because, from it's position, your screen will have infinite height.
The solution is to set the height of your inner recyclerview to some static value, not wrap_content or match parent, as either of those will simply fill up the outer recyclerview with one view that will all be bound at once due to it's large height. If you make the height of the inner recyclerview the same as the display's height, you should see your problem go away.
Here is an implementation that will not bind all children at once:
<RecyclerView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical>
<View .../>
<!-- other stuff -->
<RecyclerView
android:layout_width="match_parent"
android:layout_height="#dimen/screen_height"
android:orientation="vertical"/>
</RecyclerView>
Note the layout_height of the inner RecyclerView is now a fixed value pulled from the dimensions file. You yourself will have to come up with a reasonable value to put there.
Side Note: In order to make all of this work and for scrolling to work properly, you may have to play around with the parameter: NestedScrollingEnabled in your RecyclerViews - there are several known bugs relating to this that you may need to work around.
i.e.: innerRecyclerView.setHasFixedSize(true); and innerRecyclerView.setNestedScrollingEnabled(false).
so what happens here when you place a scrollview(no fixed size because of wrap content) inside another scrollview(again no fixed size because of wrap content),both nested scroll view fails to render.
So there is two solutions--
1- Either you will have to think of alternative solution for nested scrollviews
2- You can give outside recyclerview cell fixed height so that inside recycler view can get some fixed layout to render itself.
I could solve my issue by using only one Recyclerview, where it has a grid layout, and based on the component items i'm adding into it, i change the spancount for that. Basically instead of adding the inner recyclerview, i add the items that were supposed to go to the inner recyclerview, to the outer recyclerview.
Im creating RecyclerView and ListView inside ScrollView and im getting problems with the scroll.. The scroll is Jerking (unable to get smooth scroll), I know its the problem with the RecyclerView inside the ScrollView, because layout is scrolling without any problem when swiping until the ListView exists but once RecyclerView items enter the layout it starts to jerk( only scrolling with the finger, no proper scroll when finger is taken off). Here is the code in the xml
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/lv_home_dropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#color/colorWhite"
android:dividerHeight="0.5dp"
android:visibility="gone"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycleView"
android:background="#color/colorWhite">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</ScrollView>
Nested views that scroll along the same axis have always been
problematic on Android. Recently Google has added nested scrolling
support. In order to have this on older platform levels, you should
use the views in the support library like NestedScrollView and
RecyclerView.
ListView does not work with wrap_content as its height. You can do
this with RecyclerView if you have the latest version of the
RecyclerView support library. Besides, you are already using RecyclerView in one place, you might as well use them exclusively.
ListView is not really meant to be a "drop down". Perhaps you should consider a Spinner instead.
I have it finally.!!
Just add the following line of code in you class where you are calling the RecyclerView
mRecyclerView = (RecyclerView)tmpView.findViewById(R.id.recycleView);
mRecyclerView.setNestedScrollingEnabled(false);
It works for me!
In my Android app running on Android 5.1.1 I have a layout using a Toolbar with a TabLayout, and underneath is a ViewPager. All of these are put together in a CoordinatorLayout.
In the first page of the ViewPager is a RecyclerView serving CardView items.
My problem is that my ViewPager keeps getting resized in a way so that my CardView list items are cropped.
My main layout looks basically like this:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
And the first fragment served by my ViewPager looks like:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"/>
</FrameLayout>
This renders something that looks like this:
When clicking a button in my layout, I use startActivityForResult to invoke another activity, and when returning to my activity sometimes suddenly my list is cropped so that only half of the first item is visible:
After swiping horizontally to another pager in the ViewPager and then back, the problem disappears, so it does seem a re-layout has not been properly triggered. Pressing HOME and then resuming my activity does NOT resolve the problem though. Note that this happens even if I am not modifying my layout in any way, I am simply returning from a startActivityForResult call. And yes, it only happens sometimes... And I have no background threads running that could explain the apparent random behavior.
At first I thought it was the RecyclerView that had shrunk, but using HierarchyViewer I was able to find that it was actually the entire ViewPager that had shrunk to about half its original height.
I tried various hacks to get around this, including calling invalidate() and requestLayout() on my entire view hiearchy, but nothing seemed to help (although swiping to another page and back again fixes it). Also, those are not the kind of solutions I want to resort to... Then I tried changing my ViewPager height to wrap_content, which did in fact solve this particular problem; after returning to my activity the first item in my RecyclerView is never cropped, and I can scroll down to the other items. However, now instead the very last item of my list is always cropped, as can be seen in this screenshot where the list is scrolled all the way to the bottom:
Since I am now at a point where I don't really understand what's going on, I need some help. What should I really use as the layout_height for my ViewPager, and - above all - why? To me, match_parent makes sense, but how should I be thinking here? Is there a rational reason my views got cropped when using match_parent, or did I in fact encounter a bug in ViewPager, RecyclerView and/or CoordinatorLayout? How do I make sure that my ViewPager consistently fills the entire screen area below the AppBar, and that my RecyclerView can be scrolled vertically to properly render all CardView list items?
It turns out this is almost certainly a bug in CoordinatorLayout or even more likely in AppBarLayout$ScrollingViewBehavior. In an effort to create a MCVE I realized it was the fact that my sub-activity had an IME on screen that caused the shrinking of the ViewPager - when my activity is resumed after onActivityResult, the ViewPager is shrunk as a result of reduced screen real-estate from the IME, but is never expanded again despite the fact that the IME is no longer being shown and the fact that the CoordinatorLayout is indeed expanded.
After debugging and stepping through onLayout and onMeasure of CoordinatorLayout and ViewPager I am now fairly sure that the CoordinatorLayout does not properly propagate the change in size to its children.
I found that I can "fix" the problem by calling requestLayout on my ViewPager, but only if the call is sufficiently delayed (10 ms never works, 100 ms works most of the time):
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mViewPager.requestLayout();
}
}, 100);
}
This obviously isn't a robust solution, but after investigating some more it turns out I probably don't even need CoordinatorLayout since I don't really have any advanced scrolling behavior. So my solution will be to simply go with a LinearLayout or RelativeLayout as my root view group instead. Nice and simple, no need to complicate things.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
I will however try to condense this into a simple example and file a bug with Google.
As to what I should use as the height for my ViewPager, my original use of match_parent still seems reasonable. The fact that wrap_content solved the problem (but caused other problems) is probably just due to inconsistencies caused by the bug.
I've experienced a similar issue when using an older version of the support library.
See these related issues:
https://code.google.com/p/android/issues/detail?id=176406
https://code.google.com/p/android/issues/detail?id=176187
Make sure you're using the latest Support library, version 23.1 as of this writing.
In your fragment just remove the frameLayout and make recyclerView parent...I hope it will work:
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp">
<android.support.v7.widget.RecyclerView/>
I am using an NSV in a CL for the ability to have the toolbar compress when the NSV scrolls down. The problem that I am having is that my NSV is not scrolled to the top when it loads, instead, it is offset from the top of the NSV by quite a margin (I am not certain where this spacing is coming from, it's not in the layout).
Please take a look at the screen captures, the first one shows how the NSV loads and you can clearly see the NSV has scrolled down quite a bit from the top by comparing the second (when I scroll the NSV to the top manually):
I did some updates to this layout and it caused this to occur, previously, it loaded at the top without issue. However, I did not add any spacing that should have caused this.
Here is the layout I'm using for this:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/cl_goal_detail"
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="0dp"
android:layout_weight="1">
<android.support.design.widget.AppBarLayout
android:id="#+id/abl_goal_detail"
android:layout_width="match_parent"
android:layout_height="144dp"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar_goal_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/content_space_double"
app:collapsedTitleTextAppearance="#style/title.dark"
app:expandedTitleTextAppearance="#style/display3.plus.dark"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_goal_detail"
style="#style/toolbar"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/nsv_goal_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/content_space_half"
android:paddingLeft="#dimen/content_space_half"
android:paddingRight="#dimen/content_space_half"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/container_goal_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Any ideas would be appreciated!
OK! After a solid DAY of debugging every single component of my layout and Fragment I identified what I believe is a bug.
First, the issue: Turns out that having elements in your NSV's child view that change visibility to View.GONE upon runtime are causing the list to scroll down. I noticed that the list scrolls to just above the element where the visibility was toggled (including any margins set on the view).
Second, the fix: I fixed this issue by setting all the views to have android:visibility="gone" in the xml layout, then, I toggle each view's visibility as needed. Previously, the views were visible by default and then I worked from there. I just needed to change my logic to start with them all GONE, not terribly difficult.
I assume this works because the views you are going to hide at runtime do not form a part of the overall height calculation when the NSV is created in onCreateView(). Once the fragment progresses past onCreateView() it's safe to dynamically change the views, however, if the views are calculated as part as the height in onCreateView() and THEN hidden with View.GONE, measurements go wonky and you end up with a list scrolled down significantly.
Have you tried adding below line in your viewgroup i.e. FrameLayout in your case
android:descendantFocusability="blocksDescendants"
I think this will also work for you.
If not try it adding in NSV.
In my case, there was an EditText near the bottom of my scrolling content that was grabbing focus. Since NestedScrollView does some weird layout stuff, the focused view didn't scroll to the top when the activity started, so the real cause was not readily apparent. Adding this to the NestedScrollView's child layout fixed it for me:
android:focusableInTouchMode="true"
Your post answer helped me a lot to find out my issue (btw, it was the same). But I got it worked in a different way. I guess you are using a RecyclerView. In my case I'm using 3 RecyclerViews. Well, from your answer I started hiding the recyclers and I found out just one of them was causing this issue. What I did is I populated with a postDelayed:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
recyler.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyler.setAdapter(new MyAdapter(myList));
}
}, 3000);
That worked fine!