Android – RecyclerView inside NestedScrollView Example

In android, there are times when you will have the need to add RecyclerView inside a NestedScrollView. The problem that usually arise is that both RecyclerView and NestedScrollView support ScrollView.

When you have one inside the other, the scrolling of the layout will become slacking and jumpy most time. This is because the RecyclerView and the NestedScrollView and responding to the same scroll gesture.

Please not that it is important you use the android support library 23 or above

How can we mitigate this problem and still use android RecyclerView inside NestedScrollView?

Before I go further to give you an idea of what we can do, I will like you to see an example of the application we will use to test this concept.

We are going to add a LinearLayout as a child to NestedScrollView. Inside the LinearLayout, add an ImageView on top and RecyclerView under it.

The screen-shot is shown below.

Android nestedscrollview

1. Create a new android project

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidNestedScrollView

Package: com.inducesmile.androidnestedscrollview

Select Empty Activity

Name your activity: MainActivity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

2. Update strings.xml resource file

Open the strings.xml file and add the code below.

<string name="app_name">Android NestedScrollView</string>
<resources>
    <string name="app_name">Android NestedScrollView</string>
    <string name="tech_laptop">Tech Laptop</string>
</resources>

 3. Update colors.xml resource file

Open the colors.xml resource file and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
</resources>

4. Update build.gradle file

We are going to add third party library as dependency in our project build.gradle. Open the build.gradle file and update the code as shown below.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.inducesmile.androidnextedscrollview"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.1'
    compile 'com.android.support:design:25.1.1'
    compile 'com.android.support:cardview-v7:25.1.1'
    compile 'com.android.support:recyclerview-v7:25.1.1'
    compile 'com.intuit.sdp:sdp-android:1.0.3'
    testCompile 'junit:junit:4.12'
}

5. Update activity_main.xml

As I mention earlier, we are going to add LinearLayout in our NestedScrollView. Then inside the LinearLayout, add ImageView and RecyclerView.

Open the activity_main.xml and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.inducesmile.androidnextedscrollview.MainActivity">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:focusableInTouchMode="true"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/top_seller"
                android:layout_width="match_parent"
                android:layout_height="@dimen/_200sdp"
                android:background="@color/colorAccent"
                android:contentDescription="@string/app_name"
                android:adjustViewBounds="true"
                android:src="@drawable/laptop"
                android:scaleType="fitXY"/>

            <android.support.v7.widget.RecyclerView
                android:id="@+id/product_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:scrollbars="none" />

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</LinearLayout>

 6. Update product_item_list.xml

Here, we are going to create a layout for the each item view in the Recyclerview. If you check in the build.gradle file, we added support for android CardView. We are going to use the CardView to wrap each individual items of the RecyclerView.

Create a new layout file and name it product_item_list or any name of your choice. Open the file and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/direction_card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="1dp"
    card_view:cardElevation="@dimen/_3sdp"
    card_view:cardUseCompatPadding="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/_4sdp"
        android:layout_marginTop="@dimen/_4sdp"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="@dimen/_8sdp">

        <ImageView
            android:id="@+id/product_image"
            android:layout_width="@dimen/_150sdp"
            android:layout_height="@dimen/_100sdp"
            android:adjustViewBounds="true"
            android:contentDescription="@string/app_name"
            android:src="@drawable/lap1" />

        <TextView
            android:id="@+id/product_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/_10sdp"
            android:text="@string/tech_laptop"
            android:textColor="@color/colorPrimaryDark"
            android:textSize="@dimen/_12sdp"
            android:textStyle="bold" />

    </LinearLayout>

</android.support.v7.widget.CardView>

 7. Create RecyclerView Adapter Class

Create a new java class file and name it ProductAdapter.java. Let this class extends the android default RecyclerView Adapter class. Ovverride the required method and complete the code content as shown below.

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;

public class ProductAdapter extends RecyclerView.Adapter<ProductViewHolder>{
    private static final String TAG = ProductAdapter.class.getSimpleName();
    private Context context;
    private List<ProductObject> productList;

    public ProductAdapter(Context context, List<ProductObject> productList) {
        this.context = context;
        this.productList = productList;
    }

    @Override
    public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_item_list, parent, false);
        return new ProductViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ProductViewHolder holder, int position) {
        ProductObject productObject = productList.get(position);
        int imageRes = getResourceId(context, productObject.getImagePath(), "drawable", context.getPackageName());
        holder.productImage.setImageResource(imageRes);
        holder.productName.setText(productObject.getName());
    }

    @Override
    public int getItemCount() {
        return productList.size();
    }

    public static int getResourceId(Context context, String pVariableName, String pResourcename, String pPackageName) throws RuntimeException {
        try {
            return context.getResources().getIdentifier(pVariableName, pResourcename, pPackageName);
        } catch (Exception e) {
            throw new RuntimeException("Error getting Resource ID.", e);
        }
    }
}

8. Create new ViewHolder Java Class

Create a new java class file and name it ProductViewHolder or any name of your choice.

Open the class and add the code below in it.

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class ProductViewHolder extends RecyclerView.ViewHolder {
    public ImageView productImage;
    public TextView productName;

    public ProductViewHolder(View itemView) {
        super(itemView);
        productImage = (ImageView)itemView.findViewById(R.id.product_image);
        productName = (TextView)itemView.findViewById(R.id.product_name);
    }
}

9. Create a Product Entity Object Class

Create a new Java class file that will house the Product object details. The productObject class will have the product image and name properties.

Open the new created java class file and add the code below.

public class ProductObject {
    private String imagePath;
    private String name;
    public ProductObject(String name, String imagePath) {
        this.imagePath = imagePath;
        this.name = name;
    }
    public String getImagePath() {
        return imagePath;
    }
    public String getName() {
        return name;
    }
}

10. Update MainActivity.java class

Finally, we are going to update the MainActivity class. Get the instance of the RecyclerView object. We have to create an instance of a GridLayoutManager and set it to the RecyclerView object.

This is where the main tricks lies. In other to enjoy smooth scrolling with the android RecyclerView put inside the NestedScrollView, we are going to set the method setNestedScrollingEnabled(false) to false

Finally, set the ProductAdapter instance to the RecyclerView object by call the setAdapter() method of the class.

Open the MainActivity class and update the code as shown below.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RecyclerView bestRecyclerView = (RecyclerView)findViewById(R.id.product_list);
        GridLayoutManager mGrid = new GridLayoutManager(this, 2);
        bestRecyclerView.setLayoutManager(mGrid);
        bestRecyclerView.setHasFixedSize(true);
        bestRecyclerView.setNestedScrollingEnabled(false);
        ProductAdapter mAdapter = new ProductAdapter(MainActivity.this, getProductTestData());
        bestRecyclerView.setAdapter(mAdapter);
    }

    private List<ProductObject> getProductTestData() {
        List<ProductObject> featuredProducts = new ArrayList<ProductObject>();
        featuredProducts.add(new ProductObject("Gig Laptop", "lap1"));
        featuredProducts.add(new ProductObject("Mash Laptop", "lap1"));
        featuredProducts.add(new ProductObject("Blue Dot Lapto", "lap1"));
        featuredProducts.add(new ProductObject("Skin Laptop", "lap1"));
        featuredProducts.add(new ProductObject("Dice Laptop", "lap1"));
        featuredProducts.add(new ProductObject("Ingrate Laptop", "lap1"));
        featuredProducts.add(new ProductObject("Mush Laptop", "lap1"));
        featuredProducts.add(new ProductObject("Stained Laptop", "lap1"));
        return featuredProducts;
    }
}

Have you used a modified or different way to add a RecyclerView inside NestedScrollView in android? We will like you to share the method you have used with us.

Remember to subscribe to be among the first that receive current post on everything mobile app development and offers.

One Response

Add a Comment