In this tutorial I will create a simple Sectioned RecyclerView that will show 2 sections and a few items in each section and how to move an item from one section to another.
Note: For RecyclerView I used AndroidX imports and not android.support.v7.widget.RecyclerView
Setup
We need to import the recycler view from AndroidX. The build.gradle file should look like the following:
apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "com.example.sectionedrecyclerview" minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.recyclerview:recyclerview:1.1.0-beta01' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' }
The main screen
The following xml describes how the main screen should look like. The main screen contains the RecyclerView we want to display.
activity_main.xml
<?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" android:background="@android:color/white" android:padding="10dp"> <Button android:id="@+id/button" android:text="Move Item" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/sectioned_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
Below we will create the xml layout for a section. It will contain a TextView for section title and a RecyclerView for the list of items within the section.
list_section.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/section_item_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/item_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="7dp" /> </LinearLayout>
The section
list_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/list_item_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
Now we will create a Section model that will contain:
- the section title
- the items that will show in a section.
Section.java
package com.example.sectionedrecyclerview; import java.util.List; public class Section { private String sectionTitle; private List<String> allItemsInSection; public Section(String sectionTitle, List<String> allItemsInSection) { this.sectionTitle = sectionTitle; this.allItemsInSection = allItemsInSection; } public String getSectionTitle() { return sectionTitle; } public void setSectionTitle(String sectionTitle) { this.sectionTitle = sectionTitle; } public List<String> getAllItemsInSection() { return allItemsInSection; } public void setAllItemsInSection(List<String> allItemsInSection) { this.allItemsInSection = allItemsInSection; } }
And here is the important part of the tutorial. For a sectioned RecyclerView we will need to create 2 adapters: one for the items within a section, and one for the sections.
ItemAdapter.java
package com.example.sectionedrecyclerview; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.util.List; public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> { List<String> items; public ItemAdapter(List<String> items) { this.items = items; } @NonNull @Override public ItemAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ItemAdapter.ViewHolder holder, int position) { String itemName = items.get(position); holder.bind(itemName); } @Override public int getItemCount() { return items.size(); } public class ViewHolder extends RecyclerView.ViewHolder { private TextView itemName; public ViewHolder(@NonNull View itemView) { super(itemView); itemName = itemView.findViewById(R.id.list_item_text_view); } public void bind(String item) { itemName.setText(item); } } }
Let’s create the adapter for our sections!
SectionAdapter.java
package com.example.sectionedrecyclerview; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.List; public class SectionAdapter extends RecyclerView.Adapter<SectionAdapter.ViewHolder> { private List<Section> sectionList; private Context context; private ItemAdapter itemAdapter; public SectionAdapter(Context context, List<Section> sections) { sectionList = sections; this.context = context; } @NonNull @Override public SectionAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_section, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Section section = sectionList.get(position); holder.bind(section); } @Override public int getItemCount() { return sectionList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { private TextView sectionName; private RecyclerView itemRecyclerView; public ViewHolder(@NonNull View itemView) { super(itemView); sectionName = itemView.findViewById(R.id.section_item_text_view); itemRecyclerView = itemView.findViewById(R.id.item_recycler_view); } public void bind(Section section) { sectionName.setText(section.getSectionTitle()); // RecyclerView for items LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); itemRecyclerView.setLayoutManager(linearLayoutManager); itemAdapter = new ItemAdapter(section.getAllItemsInSection()); itemRecyclerView.setAdapter(itemAdapter); } } public void moveItem(int toSectionPosition, int fromSectionPosition) { List<String> toItemsInSection = sectionList.get(toSectionPosition).getAllItemsInSection(); List<String> fromItemsInSection = sectionList.get(fromSectionPosition).getAllItemsInSection(); if (fromItemsInSection.size() > 3) { toItemsInSection.add(fromItemsInSection.get(3)); fromItemsInSection.remove(3); // update adapter for items in a section itemAdapter.notifyDataSetChanged(); // update adapter for sections this.notifyDataSetChanged(); } } }
Now in the MainActivity class we should setup the sections list and populate both sections and items lists with data. In our examples we will just add hardcoded data using 2 for loops :)
MainActivity.java
package com.example.sectionedrecyclerview; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.os.Bundle; import android.view.View; import android.widget.Button; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private List<String> itemArrayList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.sectioned_recycler_view); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(linearLayoutManager); final List<Section> sections = new ArrayList<>(); //add sections for (int i = 0; i <= 1; i++) { itemArrayList = new ArrayList<>(); //add items to a section for (int j = 0; j <= 4; j++) { itemArrayList.add("Item " + j + " Section " + i); } //add the section and items to array list sections.add(new Section("Section " + i, itemArrayList)); } final SectionAdapter adapter = new SectionAdapter(this, sections); recyclerView.setAdapter(adapter); Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (itemArrayList.size() > 3) { adapter.moveItem(0, 1); } } }); } }
You can take a look below at our very simple Sectioned RecyclerView :)