RecyclerView Overview:
RecyclerView simplifies data display and management in two key ways:
- It utilizes LayoutManager to determine the arrangement of each item.
- It provides default animation effects for adding and removing items, which can also be customized.
RecyclerView Architecture:
Adapter: Before using RecyclerView, you need an adapter that extends RecyclerView.Adapter. Its purpose is to bind data with the interface of each item.
LayoutManager: This component determines how each item is arranged, displayed, and hidden.
Adding Items to RecyclerView:
Add the following code to you're adapter:
// Add new item
public void insertItem(int position) {
// Add data to the list and notify about the new item
itemsList.add(position, "Product " + position);
// Trigger insertion animation
notifyItemInserted(position);
}
When calling:
adapter.insertItem(itemsList.size());
Removing Items from RecyclerView:
Add the following code to your adapter:
// Remove item
public void deleteItem(int position) {
itemsList.remove(position);
// Trigger removal animation
notifyItemRemoved(position);
// Refresh entire dataset to prevent index issues
notifyDataSetChanged();
}
When calling:
// Delete from within an item
deleteItem(position);
// Delete from external controls
adapter.deleteItem(position);
Note: I've added notifyDataSetChanged() after the removal animation. This is important because when we delete items, they might not be removed sequentialy, which could cause index out of bounds exceptions due to position mismatches. A full refresh prevents this issue.
Complete Implementation:
1. MainActivity
package com.example.recyclerviewdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageButton;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView productRecyclerView;
private ImageButton addButton;
private ProductAdapter adapter;
private List<string> itemsList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeViews();
setupRecyclerView();
addButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Add with default animation
adapter.insertItem(itemsList.size());
}
});
}
private void setupRecyclerView() {
// Set up vertical scrolling
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
productRecyclerView.setLayoutManager(layoutManager);
// Get data, pass to adapter, and bind adapter
itemsList = generateData();
adapter = new ProductAdapter(MainActivity.this, itemsList);
productRecyclerView.setAdapter(adapter);
// Add animations
productRecyclerView.setItemAnimator(new DefaultItemAnimator());
}
private void initializeViews() {
addButton = findViewById(R.id.add_button);
productRecyclerView = findViewById(R.id.products_recycler_view);
}
protected ArrayList<string> generateData() {
ArrayList<string> dataItems = new ArrayList<>();
for (int i = 0; i < 1; i++) {
dataItems.add("Product " + i);
}
return dataItems;
}
}
</string></string></string>
2. ProductAdapter
package com.example.recyclerviewdemo;
import android.content.Context;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
class ProductAdapter extends RecyclerView.Adapter<productadapter.itemviewholder> {
private Context context;
private List<string> itemsList;
public ProductAdapter(Context context, List<string> itemsList) {
this.context = context;
this.itemsList = itemsList;
}
@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ItemViewHolder holder = new ItemViewHolder(LayoutInflater.from(
context).inflate(R.layout.item_product, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(ItemViewHolder holder, final int position) {
holder.productName.setText(itemsList.get(position));
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (itemsList.size() == 1) {
Snackbar.make(v, "This item cannot be deleted", Snackbar.LENGTH_SHORT).show();
} else {
// Delete with default animation
deleteItem(position);
}
}
});
}
@Override
public int getItemCount() {
return itemsList.size();
}
// Add new item
public void insertItem(int position) {
// Add data to the list and notify about the new item
itemsList.add(position, "Product " + position);
// Trigger insertion animation
notifyItemInserted(position);
}
// Remove item
public void deleteItem(int position) {
itemsList.remove(position);
// Trigger removal animation
notifyItemRemoved(position);
// Refresh entire dataset to prevent index issues
notifyDataSetChanged();
}
/**
* ViewHolder class for caching views
*/
class ItemViewHolder extends RecyclerView.ViewHolder {
TextView productName, deleteButton;
// Full refresh is needed because deleting middle items can cause index out of bounds exceptions
public ItemViewHolder(View view) {
super(view);
productName = view.findViewById(R.id.product_name);
deleteButton = view.findViewById(R.id.delete_button);
}
}
}
</string></string></productadapter.itemviewholder>