Saturday, 18 February 2017

Load More RecyclerView and Bottom ProgressBar

If we have a project with a requirement that get list user from web service then user RecyclerView to show users. When scroll RecyclerView to the end we need connect to web service to get more data and update RecyclerView. When connect to web service to get more data we should have a notice to user that load more data in progress.

In this scenario, I believe best way to show notice to user is use a progress bar showing at bottom. In this blog we will implement Load More RecyclerView with Progress bar showing at bottom.

Step 1 : Create Android Project with Android Studio

Create a new project with name LoadMoreRecyclerView, minimum SDK is API 15 Android 4.0.3

Step 2 : Add Library for this project

We must declare library for this project. Open build.gradle file and edit.


compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:design:24.2.1'
    compile 'com.android.support:cardview-v7:24.2.1'
    compile 'com.android.support:recyclerview-v7:24.2.1'

Step 3 : Create a model object 

Create a class with name User


public class User {  
 private String name;
 private String email;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}


Step 4 : Create a new Interface for callback

Create a new class with name OnLoadMoreListener and abstract method onLoadMore()


public interface OnLoadMoreListener {  
  void onLoadMore();
}

Step 5 : Create a layout file for Toolbar

Create a layout file with name layout_toolbar.xml that is a place to define Toolbar


<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:orientation="vertical">
  <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    android:layout_height="?android:attr/actionBarSize"
    android:background="@color/colorPrimary"/>
</LinearLayout>


Step 6 : Create layout file for RecyclerView items

RecyclerView will have two item type. The normal item that to show info of user and loading item that place at bottom to show progress bar.


Create file layout_loading_item.xml to define layout for loading item.


<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" >
  <ProgressBar android:id="@+id/progressBar1"
    android:layout_width="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_height="wrap_content" />
</LinearLayout>



Create file layout_user_item.xml to define layout for user item


<?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:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  card_view:cardCornerRadius="5dp"
  card_view:cardUseCompatPadding="true">
  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:selectableItemBackground">
    <TextView android:id="@+id/tvName"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margin="5dp"
      android:text="Name"
      android:textColor="@android:color/black"
      android:textSize="18sp" />
    <TextView android:id="@+id/tvEmailId"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_below="@+id/tvName"
      android:layout_margin="5dp"
      android:text="Email Id"
      android:textColor="@android:color/black"
      android:textSize="12sp" />
  </RelativeLayout>
</android.support.v7.widget.CardView>

Step 7 : Add RecyclerView to layout

To add RecyclerView to layout, open activity_main.xml file and edit:


<?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=".MainActivity">
  <include layout="@layout/layout_toolbar" />
  <android.support.v7.widget.RecyclerView
    android:id="@+id/recycleView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp" />
</LinearLayout>  

Step 8 : Initialize RecyclerView in java code


In this recyclerView we have 2 item type then must create two ViewHolder like below: 

Create LoadingViewHolder class that is an inner class in MainActivity


static class LoadingViewHolder extends RecyclerView.ViewHolder {
  public ProgressBar progressBar;
  public LoadingViewHolder(View itemView) {
   super(itemView);
   progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
  }
 }

Create UserViewHolder class that is an inner class in MainActivity


static class UserViewHolder extends RecyclerView.ViewHolder {
  public TextView tvName;
  public TextView tvEmailId;
  public UserViewHolder(View itemView) {
   super(itemView);
   tvName = (TextView) itemView.findViewById(R.id.tvName);
   tvEmailId = (TextView) itemView.findViewById(R.id.tvEmailId);
  }
 }

Like ListView, we must create a Adapter for RecyclerView. Create UserAdapter class that is an inner class in MainActivity


class UserAdapter extends RecyclerView.Adapter < RecyclerView.ViewHolder > {  
 @Override public int getItemViewType(int position) {
  return super.getItemViewType(position);
 }
 @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  return null;
 }
 @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
 @Override public int getItemCount() {
  return 0;
 }
}

In this adapter, declare two constants that is delegate for two item type of RecyclerView.


private final int VIEW_TYPE_ITEM = 0;  
private final int VIEW_TYPE_LOADING = 1;

Declare an object OnLoadMoreListener for adapter and add set method


private OnLoadMoreListener mOnLoadMoreListener;
 public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
  this.mOnLoadMoreListener = mOnLoadMoreListener;
 }

Full code for adapter :


class UserAdapter extends RecyclerView.Adapter < RecyclerView.ViewHolder > {
  private final int VIEW_TYPE_ITEM = 0;
  private final int VIEW_TYPE_LOADING = 1;
  private OnLoadMoreListener mOnLoadMoreListener;
  private boolean isLoading;
  private int visibleThreshold = 5;
  private int lastVisibleItem, totalItemCount;

  public UserAdapter() {
   final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
   mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
     super.onScrolled(recyclerView, dx, dy);
     totalItemCount = linearLayoutManager.getItemCount();
     lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
     if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
      if (mOnLoadMoreListener != null) {
       mOnLoadMoreListener.onLoadMore();
      }
      isLoading = true;
     }
    }
   });
  }
  public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
   this.mOnLoadMoreListener = mOnLoadMoreListener;
  }
  @Override public int getItemViewType(int position) {
   return mUsers.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
  }
  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
   if (viewType == VIEW_TYPE_ITEM) {
    View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_user_item, parent, false);
    return new UserViewHolder(view);
   } else if (viewType == VIEW_TYPE_LOADING) {
    View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_loading_item, parent, false);
    return new LoadingViewHolder(view);
   }
   return null;
  }
  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
   if (holder instanceof UserViewHolder) {
    User user = mUsers.get(position);
    UserViewHolder userViewHolder = (UserViewHolder) holder;
    userViewHolder.tvName.setText(user.getName());
    userViewHolder.tvEmailId.setText(user.getEmail());
   } else if (holder instanceof LoadingViewHolder) {
    LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
    loadingViewHolder.progressBar.setIndeterminate(true);
   }
  }
  @Override public int getItemCount() {
   return mUsers == null ? 0 : mUsers.size();
  }
  public void setLoaded() {
   isLoading = false;
  }
 }

Now we edit code in MainActivity to init RecyclerView, I will show full code of MainActivity.java :


import android.os.Bundle;  
import android.os.Handler;  
import android.support.v7.app.AppCompatActivity;  
import android.support.v7.widget.LinearLayoutManager;  
import android.support.v7.widget.RecyclerView;  
import android.support.v7.widget.Toolbar;  
import android.util.Log;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.widget.ProgressBar;  
import android.widget.TextView;  
import net.awpspace.loadmorerecycleview.listener.OnLoadMoreListener;  
import net.awpspace.loadmorerecycleview.model.User;  
import java.util.ArrayList;  
import java.util.List;  
public class MainActivity extends AppCompatActivity {  
 private Toolbar mToolbar;
 private RecyclerView mRecyclerView;
 private List < User > mUsers = new ArrayList < > ();
 private UserAdapter mUserAdapter;
 @Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mToolbar = (Toolbar) findViewById(R.id.toolbar);
  mToolbar.setTitle("LoadMoreRecycleView");
  for (int i = 0; i < 30; i++) {
   User user = new User();
   user.setName("Name " + i);
   user.setEmail("abhishek" + i + "@gmail.com");
   mUsers.add(user);
  }
  mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
  mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
  mUserAdapter = new UserAdapter();
  mRecyclerView.setAdapter(mUserAdapter);
  mUserAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
   @Override public void onLoadMore() {
    Log.e("haint", "Load More");
    mUsers.add(null);
    mUserAdapter.notifyItemInserted(mUsers.size() - 1);
    //Load more data for reyclerview
    new Handler().postDelayed(new Runnable() {
     @Override public void run() {
      Log.e("haint", "Load More 2");
      //Remove loading item
      mUsers.remove(mUsers.size() - 1);
      mUserAdapter.notifyItemRemoved(mUsers.size());
      //Load data 
      int index = mUsers.size();
      int end = index + 20;
      for (int i = index; i < end; i++) {
       User user = new User();
       user.setName("Name " + i);
       user.setEmail("abhishek" + i + "@gmail.com");
       mUsers.add(user);
      }
      mUserAdapter.notifyDataSetChanged();
      mUserAdapter.setLoaded();
     }
    }, 5000);
   }
  });
 }
 static class UserViewHolder extends RecyclerView.ViewHolder {
  public TextView tvName;
  public TextView tvEmailId;
  public UserViewHolder(View itemView) {
   super(itemView);
   tvName = (TextView) itemView.findViewById(R.id.tvName);
   tvEmailId = (TextView) itemView.findViewById(R.id.tvEmailId);
  }
 }
 static class LoadingViewHolder extends RecyclerView.ViewHolder {
  public ProgressBar progressBar;
  public LoadingViewHolder(View itemView) {
   super(itemView);
   progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
  }
 }
 class UserAdapter extends RecyclerView.Adapter < RecyclerView.ViewHolder > {
  private final int VIEW_TYPE_ITEM = 0;
  private final int VIEW_TYPE_LOADING = 1;
  private OnLoadMoreListener mOnLoadMoreListener;
  private boolean isLoading;
  private int visibleThreshold = 5;
  private int lastVisibleItem, totalItemCount;

  public UserAdapter() {
   final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
   mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
     super.onScrolled(recyclerView, dx, dy);
     totalItemCount = linearLayoutManager.getItemCount();
     lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
     if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
      if (mOnLoadMoreListener != null) {
       mOnLoadMoreListener.onLoadMore();
      }
      isLoading = true;
     }
    }
   });
  }
  public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
   this.mOnLoadMoreListener = mOnLoadMoreListener;
  }
  @Override public int getItemViewType(int position) {
   return mUsers.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
  }
  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
   if (viewType == VIEW_TYPE_ITEM) {
    View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_user_item, parent, false);
    return new UserViewHolder(view);
   } else if (viewType == VIEW_TYPE_LOADING) {
    View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_loading_item, parent, false);
    return new LoadingViewHolder(view);
   }
   return null;
  }
  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
   if (holder instanceof UserViewHolder) {
    User user = mUsers.get(position);
    UserViewHolder userViewHolder = (UserViewHolder) holder;
    userViewHolder.tvName.setText(user.getName());
    userViewHolder.tvEmailId.setText(user.getEmail());
   } else if (holder instanceof LoadingViewHolder) {
    LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
    loadingViewHolder.progressBar.setIndeterminate(true);
   }
  }
  @Override public int getItemCount() {
   return mUsers == null ? 0 : mUsers.size();
  }
  public void setLoaded() {
   isLoading = false;
  }
 }
}



You can get complete code in here: github

#HAPPYCODING

Friday, 17 February 2017

spinner in recyclerview android

spinner in recyclerview android


Hi friends!! hope you are guys doing awesome!! Here's complete guide about using spinner in recyclerview.

Please follow the steps below to get desired outcome

1. The very first step would be to create a new Android Studio Project. As it is quite obvious, i won't show up here but if anyone finds any difficulties, do let me know.

2. After creating New Project, open build.gradle from your app and then paste these lines of code. You may have different versions of gradle files as per your gradle libraries installed.

compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.android.support:support-v4:24.2.1'
    compile 'com.android.support:design:24.2.1'
    compile 'com.android.support:recyclerview-v7:24.2.1'

3. Now open your activity_main.xml and paste these lines of codes.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.abhishek.spinnerinrecyclerview.MainActivity">
    
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

</RelativeLayout>

4. Now open your MainActivity.class and paste these codes.


package com.abhishek.spinnerinrecyclerview;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Spinner;

public class MainActivity extends AppCompatActivity {

    Spinner spinner;
    private Context mContext;
    private RecyclerView recycler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        
        recycler = (RecyclerView)findViewById(R.id.recycler);
        recycler.setLayoutManager(new LinearLayoutManager(mContext));
        UserAdapter userAdapter = new UserAdapter(mContext, User.getUserList());
        recycler.setAdapter(userAdapter);

    }



}

5. Now create UserAdapter class for displaying recycler view data and paste these codes.


package com.abhishek.spinnerinrecyclerview;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

import java.util.List;

/**
 * Created by Abhishek on 16/02/17.
 */

public class UserAdapter extends RecyclerView.Adapter<UserViewHolder> {

    private Context mContext;
    private List<User> userList;
    private ArrayAdapter<Customer> dataAdapter;
    public UserAdapter(Context context, List<User> userList){
        this.mContext = context;
        this.userList = userList;

        dataAdapter = new ArrayAdapter<Customer>(mContext,
                android.R.layout.simple_spinner_item, Customer.fillCustomer());
        // Drop down layout style - list view with radio button
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    }

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

    @Override
    public void onBindViewHolder(UserViewHolder holder, int position) {
        holder.tv_1.setText(""+userList.get(position).getUserId());
        holder.tv_2.setText(userList.get(position).getUserName());
        holder.spinner.setAdapter(dataAdapter);
    }

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

6. Now create UserViewHolder class and paste these codes


package com.abhishek.spinnerinrecyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Spinner;
import android.widget.TextView;

/**
 * Created by Abhishek on 16/02/17.
 */
public class UserViewHolder extends RecyclerView.ViewHolder{

    public TextView tv_1;
    public TextView tv_2;
    public Spinner spinner;

    public UserViewHolder(View itemView) {
        super(itemView);
        tv_1 = (TextView)itemView.findViewById(R.id.tv_1);
        tv_2 = (TextView)itemView.findViewById(R.id.tv_2);

        spinner = (Spinner)itemView.findViewById(R.id.spinner);

        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                // On selecting a spinner item
                String item = parent.getItemAtPosition(position).toString();
                // Showing selected spinner item
                //Toast.makeText(parent.getContext(), "Selected: " + item, Toast.LENGTH_LONG).show();

            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });

    }
}

7. Now create User class for setting recycler data.


package com.abhishek.spinnerinrecyclerview;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Abhishek on 16/02/17.
 */

public class User {

    public int userId;
    public String userName;


    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public static List<User> getUserList(){
        List<User> userList = new ArrayList<>();
        for(int i=0; i<200000; i++){
            User user = new User();
            user.setUserId(0+i);
            user.setUserName("Name: Ashu"+i);
            userList.add(user);
        }
        return userList;
    }

}

8. Now create Customer class for displaying spinner data.


package com.abhishek.spinnerinrecyclerview;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Abhishek on 16/02/17.
 */

public class Customer {

    public String id;
    public String customerName;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public static List<Customer> fillCustomer(){
        List<Customer> customerList = new ArrayList<>();
        for(int i=0; i<1000; i++){
            Customer customer = new Customer();
            customer.setId(""+i);
            customer.setCustomerName("Name"+i);
            customerList.add(customer);
        }
        return customerList;

    }

    @Override
    public String toString() {
        return customerName;
    }
}

9. Now create recycler_item.xml in layout and paste these code.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:padding="20dp"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_1"
        android:layout_width="wrap_content"
        android:text="text 1"
        android:layout_height="match_parent" />

    <TextView
        android:id="@+id/tv_2"
        android:layout_width="wrap_content"
        android:text="text 2"
        android:layout_height="match_parent" />

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent">

    </Spinner>

</LinearLayout>

10. Now run the project and get your spinner working properly in the recycler view. 

#HAPPYCODING