An android library developed to help developers select and process items presented in a RecyclerView.
The library makes it easy to
- Set the selection status of the items
- Get the selected or the unselected Items
- Remove the selected or unselected items from the arraylist
- Set background drawables for items according to their selection status
| function | Paramenters | returns | Description |
|---|---|---|---|
| selectItem | Object | void | Accepts an item and sets it as selected |
| unSelectItem | Object | void | Accepts an item and sets it as unSelected |
| selectItem | int | void | Accepts the position of an item and sets it as selected |
| unSelectItem | int | void | Accepts the position of an item and sets it as unSelected |
| reverseSelectionStatus | int | void | If an item is selected it becomes unselected and vice versa |
| reverseSelectionStatus | Object | void | If an item is selected it becomes unselected and vice versa |
| removeItem | int | void | removes an item and also unselects it. Useful if the callbacks are used |
| removeItem | Object | void | removes an item and also unselects it. Useful if the callbacks are used |
| isSelected | Object | boolean | accepts an item and checks if it is selected |
| isSelected | int | boolean | accepts the position of an item and checks if it is selected |
| getSelectedItems | - | ArrayList | returns an ArrayList with the selected items |
| getUnselectedItems | - | ArrayList | returns an ArrayList with the uSelected items |
| unSelectAllItems | - | void | unSelects all items |
| selectAllItems | - | void | selects all items |
| getSelectedItemCount | - | int | returns the count of the selected items |
| onNoItemSelected | - | void | callback that is triggered when selectedItemCount goes from >0 to 0 |
| setOnNoItemSelected | OnNoItemSelected | void | dynamically set the callback. More flexibility than overriding onNoItemSelected |
| onAtLeastOneItemSelected | - | void | callback that is triggered when selectedItemCount goes from 0 to >0 |
| setOnAtLeastOneItemSelected | OnAtLeastOneItemSelected | void | dynamically set the callback. More flexibility than overriding onAtLeastOneItemSelected |
| checkIfAllItemsSelected | - | boolean | checks if All the Items are selected |
| removeSelectedItems | - | void | removes the selected items from the item ArrayList |
| removeUnselectedItems | - | void | removes the unSelected items from the item ArrayList |
| setItemsDrawable | Drawable, Drawable | void | sets the background drawables of the selected and the unSelected items |
The library is developed so that it diverges from the classic RecyclerView-Adapter as little as possible. Let's implement a simple SelectableRecyclerView that presents an ArrayList of strings and the user can select-unselect those items by clicking one them and then delete the selected. If you already know how to set up a recyclerView move on to the Adapter and drawables sections.
-
Create a new project
- Select "Empty Activity"
- Name your app: SelectableRecyclerViewExample
- Select package name and save location
- Select java as language
-
Import the library
-
Add jitpack.io in build.gradle => allprojects => repositories among everything else you might need.
allprojects { repositories { maven { url 'https://jitpack.io' } } } -
Add implementation in build.gradle(:app) among everything else you might need.
dependencies { implementation 'com.github.dagkalis:SelectableRecyclerView:0.1.0' } -
Make sure to sync Gradle files
-
-
Make a simple a simple layout in res->layout called string_view.xml for the adapter to use to display the strings. The view should be like this:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"> <TextView android:id="@+id/textViewString" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:text="TextView" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> -
Make a new class with the name Adapter
This class will use the utilities of the library.
- Instead of extending the RecyclerView.Adapter extend the class SelectableRecyclerViewAdapter. Declaration should look like this.
public class Adapter extends SelectableRecyclerViewAdapter<Adapter.SelectableHolder> { }-
Now create the nested class SelectableHolder the same way you would if you used the recyclerView.Adapter.
public class SelectableHolder extends RecyclerView.ViewHolder { TextView string; public SelectableHolder(@NonNull View itemView) { super(itemView); string = itemView.findViewById(R.id.textViewString); } } -
Make a constructor that accepts an ArrayList of strings and the Activity context. Assign both values to class variables.
ArrayList<String> strings; Context context; public Adapter(ArrayList<String> strings, Context context) { this.strings = strings; this.context = context; } -
Override the necessary functions.
-
getItems: a functions that returns the items.
@NonNull @Override protected ArrayList getItems() { return strings; } -
onCreateViewHolder: same as classic RecyclerView.
@NonNull @Override public SelectableHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = (LayoutInflater.from(context)).inflate(R.layout.string_view, parent, false); return new SelectableHolder(view); } -
onBindSelectableViewHolder: put here the logic you would in onBindViewHolder. Also we decide that the user can select and unselect item just by clicking on it so we put the appropriate logic. We also put some toasts so the we keep track of the changes.
@Override public void onBindSelectableViewHolder(@NonNull SelectableHolder holder, int position) { holder.string.setText(strings.get(position)); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isSelected(position)){ unSelectItem(position); Toast.makeText(context, "unselected item " + position, Toast.LENGTH_SHORT).show(); }else{ selectItem(position); Toast.makeText(context, "selected item " + position, Toast.LENGTH_SHORT).show(); } notifyItemChanged(position); } }); }
-
-
Although the user can select items he can't know the selection status of each. So we make two xml drawables to differentiate between them. Make two xml files in drawable.
-
selected_item_background_drawable.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="10dp" /> <solid android:color="@color/white"/> <stroke android:width="0.1mm" android:color="#575757" /> </shape> -
un_selected_item_background_drawable.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="10dp" /> <solid android:color="#FFF"/> <stroke android:width="0.1mm" android:color="#B8B8B8" /> </shape> -
Go to the adapter and in the constructor set the drawables. Now our adapter constructor looks like this:
public Adapter(ArrayList<String> strings, Context context) { this.strings = strings; this.context = context; setItemsDrawable(ContextCompat.getDrawable(context, R.drawable.selected_item_background_drawable), ContextCompat.getDrawable(context, R.drawable.un_selected_item_background_drawable)); }
-
-
Inside activity_main.xml:
-
Insert a button to remove selected Items
<Button android:id="@+id/remove_selected_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Remove Selected" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> -
A recyclerView to present the strings
<androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/remove_selected_btn" />
-
-
Inside MainActivity.java
-
Make an ArrayList of strings and populate it with some of them.
ArrayList<String> strings = new ArrayList<>(); for(int i = 0; i < 10; i++){ strings.add("String" + i); } -
Set up the recyclerView
RecyclerView recyclerView = findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this)); Adapter adapter = new Adapter(strings, MainActivity.this); recyclerView.setAdapter(adapter); -
Setup the button so the that it removes the selected items
Button deleteSelectedButton = findViewById(R.id.remove_selected_btn); deleteSelectedButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { adapter.removeSelectedItems(); adapter.notifyDataSetChanged(); } });
-
-
Run the app
-
MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ArrayList<String> strings = new ArrayList<>(); for(int i = 0; i < 10; i++){ strings.add("String" + i); } RecyclerView recyclerView = findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this)); Adapter adapter = new Adapter(strings, MainActivity.this); recyclerView.setAdapter(adapter); Button deleteSelectedButton = findViewById(R.id.remove_selected_btn); deleteSelectedButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { adapter.removeSelectedItems(); adapter.notifyDataSetChanged(); } }); } } -
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/remove_selected_btn" /> <Button android:id="@+id/remove_selected_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Remove Selected" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> -
Adapter.java
public class Adapter extends SelectableRecyclerViewAdapter<Adapter.SelectableHolder> { ArrayList<String> strings; Context context; public Adapter(ArrayList<String> strings, Context context) { this.strings = strings; this.context = context; setItemsDrawable(ContextCompat.getDrawable(context, R.drawable.selected_item_background_drawable), ContextCompat.getDrawable(context, R.drawable.un_selected_item_background_drawable)); } @Override public void onBindSelectableViewHolder(@NonNull SelectableHolder holder, int position) { holder.string.setText(strings.get(position)); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isSelected(position)){ unSelectItem(position); Toast.makeText(context, "unselected item " + position, Toast.LENGTH_SHORT).show(); }else{ selectItem(position); Toast.makeText(context, "selected item " + position, Toast.LENGTH_SHORT).show(); } notifyItemChanged(position); } }); } @NonNull @Override protected ArrayList getItems() { return strings; } @NonNull @Override public SelectableHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = (LayoutInflater.from(context)).inflate(R.layout.string_view, parent, false); return new SelectableHolder(view); } public class SelectableHolder extends RecyclerView.ViewHolder { TextView string; public SelectableHolder(@NonNull View itemView) { super(itemView); string = itemView.findViewById(R.id.textViewString); } } } -
string_view.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"> <TextView android:id="@+id/textViewString" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:text="TextView" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> -
selected_item_background_drawable.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="10dp" /> <solid android:color="#FFC6C6"/> <stroke android:width="0.1mm" android:color="#FF8585" /> </shape> -
un_selected_item_background_drawable.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="10dp" /> <solid android:color="#FFF"/> <stroke android:width="0.1mm" android:color="#B8B8B8" /> </shape>