RecyclerView inside NestedScrollView causing slow load and/or crashing - android

I am working with a RecyclerView which will be used to load potentially many images and I'd like to have an actionbar above the RecyclerView like this:
But I'd also like the actionbar to only have that grayish background at the very top. If the user scrolls, it should be totally transparent like this:
I've accomplished what I wanted by using this as my layout (with one major issue):
fragment_recycler_gallery.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Gray bar at top -->
<View
android:id="#+id/gray_bar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#null" />
<android.support.v7.widget.RecyclerView 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/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
The NestedScrollView is key to getting my entire fragment to scroll instead of only the RecyclerView but it makes my app slow or unresponsive when loading a large set of images (500+). Is there a better way to create what I'm looking for? I've tried finding solutions but all I can find is "don't use recyclerviews inside nestedScrollViews" without any alternative solutions offered.
I'm using Glide to load the images into each ImageView(within the recyclerview) if that matters as well.
And I'm already using this on my RecyclerView as well:
mAlbumRecyclerView.setNestedScrollingEnabled(false);

Any time you use wrap_content on a RecyclerView, you're setting yourself up for performance problems. Using wrap_content completely defeats the performance improvements that you get from recycling views. So the question, then, is how you can do what you want without using wrap_content.
One thing you could do is use a FrameLayout to overlay a Toolbar on top of your RecyclerView, and then use padding on the RecyclerView (combined with android:clipToPadding="false") to make things appear to start below the actionbar. As long as your toolbar has a translucent background color, your recyclerview content will appear below it when you scroll.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?attr/actionBarSize"
android:clipToPadding="false"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
tools:listitem="#layout/itemview"/>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#1111"
app:title="Hello world"/>
</FrameLayout>

Related

remove default margin bottom from Toolbar

In my application I use the android.support.v7.widget.Toolbar for the toolbar.
Here is my layout
<?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"
tools:context="com.todo.app.MainActivity"
style="#style/MainActivityBg">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/AppTheme.AppBarOverlay"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
style="#style/AppTheme.ActionBar"/>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main"/>
and
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main"
tools:context="com.todo.app.MainActivity"
android:layout_marginTop="5dp"> <!-- for adding some space between the toolbar and the rest, and this is the cause of the problem! -->
<android.support.v7.widget.RecyclerView
android:id="#+id/task_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I try to add some space between the toolbar and the rest of the view. To do that I added 5dp in marginTop to the layout which is right under the view. And this causes this problem:
While I scrolling the view there is some space remaining under the toolbar.
In my style files xml, there is no style for margin or padding.
How I can adding some space between toolbar and the rest without trigger this problem (when I scrolling the view)?
Reason
Based on the xml files, it seems to me that:
<android.support.constraint.ConstraintLayout
...
android:layout_marginTop="5dp">
is the reason for cropping RecyclerView content.
When you set the layout_marginTop between the AppBarLayout and the upper edge of ConstraintLayout appears a 5dp high empty space.
You can confirm that by turning on one of the Android options for developers: Show Layout Bounds.
Solution
For the effect which you want to achieve try to remove android:layout_marginTop and set android:paddingTop for the RecyclerView but also set android:clipToPadding to false.
Check the gif in this SO answer.
<android.support.v7.widget.RecyclerView
android:id="#+id/task_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="5dp"
android:clipToPadding="false" />
This will allow you to add the desired space at the beginning of scrollable content but prevent cropping the items.
If the 5dp top margin isn't the problem, it may be the toolbar elevation, try to change 4dp to something much higher and check if changes your problem. Can you try same with margin top? Also a negetive margin sometimes work. Put a negetive margin on button of the toolbar and check.

Coordinator layout scroll flag to automatically show when the top is reached

I have a fragment which uses a coordinator layout to show an AppBarLayout and a recycler view like this:
The layout file is thus far:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="wrap_content"
app:elevation="4dp"
android:layout_height="wrap_content">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|snap">
<!-->Content removed<-->
</RelativeLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/fragment_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
The problem I'm having is that if I fling the recycler view so that the list scrolls all the way to the top, the AppBarLayout doesn't reveal unless I specifically pull down again. Is there a scroll flag to make the AppBarLayout come down when the recycler view reaches the top, as if it's attached to the first item in the recycler view?
No, transferring inertial is a known issue with nested scrolling in general, both with the platform APIs and those used by CoordinatorLayout.

Enable intertial scroll in NestedScrollView (Android Studio)

I have a NestedScrollView (part of the default Scrolling Activity) that contains a CoordinatorLayout and RecyclerView to display cards with some information. The layout is designed to allow the cards to go off-screen if there are too many and have the user scroll down to them, however for some reason the scroll does not have momentum to it as it should. I looked around and a previous question told how to disable the intertial scroll in a ScrollView (Android ScrollView disable Inertial scrolling), so I tried to do the opposite:
NestedScrollView mgScrollView = (NestedScrollView) findViewById(R.id.my_games_scroll_view);
mgScrollView.setSmoothScrollingEnabled(true);
But this didn't accomplish it. I tested mgScrollView.setVerticalScrollBarEnabled(true); to see if I was even applying the code to the right view, and so it happens the scrollbars didn't show up either. So now I'm confused as to whether I'm even applying those methods to the right view, but since I don't have any other ScrollViews I'm not sure where it should be if I am incorrect. I know I can add scrollbars in the xml itself but I haven't found xml code for inertial scrolling. Is there a way to add inertia through Java or xml?
Here is the code for content_my_games.xml, which is where the layouts for the cards go (not to be confused with activity_my_games.xml, which houses code for the CollapsingToolbarLayout and FAB)
Thanks
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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/my_games_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.example.abhinav.sportswowandroid.MyGamesActivity"
tools:showIn="#layout/activity_my_games">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
tools:context=".MyGamesActivity">
<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"
android:fitsSystemWindows="true"
tools:context=".MyGamesActivity"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"
/>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
Old question, but just ran into this myself. This solved it for me:
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setNestedScrollingEnabled(false);

Scroll second child in AppBarLayout

I'm trying to obtain this effect where if the user scroll a RecyclerView a certain layout scroll up together with the recycler and disappear behind a Toolbar.
A similar behavior could be obtained using the CoordinatorLayout, this would be possible by setting
app:layout_behavior="#string/appbar_scrolling_view_behavior"
on the said Recycler, and doing
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
Also, If I put a second child inside the AppBarLayout, and set app:layout_scrollFlags to it, the effect obtained is the same, with both layout scrolling together with the Recycler.
What I'm trying to achieve is to keep the first child (The toolbar) fixed in position, and let the second child (a LinearLayout) to scroll and hide behind the toolbar. Unfortunately I couldn't get to this behavior.
Is it possible without using 3rd part library?
Thanks in advance and sorry for my english.
Finally I figured out a way to achieve this behavior, by including the CoordinatorLayout in an LinearLayout and making the second child(LinearLayout) become the first, by moving the Toolbar to the extrnal(root) level
Hierarchy before:
<CoordinatorLayout>
<AppBarLayout>
<ToolBar>
<LinerarLayout>
Hierarchy after:
<LinearLayout>
<ToolBar>
<CoordinatorLayout>
<AppBarLayout>
<LinearLayout>
An exmaple:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="48dp" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorSecondaryLight"
android:orientation="vertical"
app:layout_scrollFlags="scroll"/>
</com.google.android.material.appbar.AppBarLayout>
.
.
.
.
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
Hope that helps!

Using AppBarLayout and CollapsingToolbarLayout without a toolbar

There's not many examples of these new layouts out on the Internet and those few that are out there are all based on same basic approach. How about if I don't have a proper toolbar in my app, but still want to use the cool functionalities of new material design layouts?
One thing that I've been trying out is using a MapView and RecyclerView inside CoordinatorLayout with a parallax scrolling effect. It works great, but there's a problem. If my adapter count is low, the RecyclerView doesn't remain on the bottom of screen. Here's some images to better describe the problem.
Initial screen:
RecyclerView scrolls over MapView, leaving blank space below:
Is there a way to keep RecyclerView on bottom?
My xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
<com.google.android.gms.maps.MapView
android:id="#+id/tts_main_map"
android:layout_width="match_parent"
android:layout_height="250dp"
app:layout_collapseMode="parallax" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
Try to set the android:minHeight property of the CollapsingToolbarLayout dynamically depending on how many items you have in the list. I.e. you should set (pseudo-code):
minHeight = allAvailableHeight - (oneListItemHeigh * listItemCount)
PS. It just an idea, I did not tried. But I think it should works.

Categories

Resources