If you need to present list of choices to users and allow them to choose only one option, then RecyclerView with RadiButton is the right choice to implement the feature.
In this post, I’ll show how to use RecyclerView with RadioButton using offers screens of ecommerce application where offers will be displayed in RecyclerView with each offer having a radio button, allows user to select only one offer.
The feature of single selection out of multiple options can be implemented using RecyclerView with RadioButton. Following sections explain layout xmls and classes created for implementing the single selection feature, the example displays a screen containing list of offers and radio buttons and it will display message on clicking a radio button.
Below item layout contains two text views for displaying offer and offer amount and a radio button.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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/offer_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/offer_amount_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="72dp"
android:text="Save $ "
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/offer_name" />
<TextView
android:id="@+id/offer_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toEndOf="@+id/offer_amount_txt"
app:layout_constraintTop_toBottomOf="@+id/offer_name" />
<RadioButton
android:id="@+id/offer_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginStart="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.864"
app:layout_constraintStart_toEndOf="@+id/offer_name" />
</android.support.constraint.ConstraintLayout>
Activity layout contains title text view and recycler view.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/offers_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="Choose One Offer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="@+id/offers_lst"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/offers_title"/>
</android.support.constraint.ConstraintLayout>
RecyclerView adapter populates data in the item layout views from the given list of items. Since RadioButtonGroup can’t be used with recycler view for single selection, we need to implement logic to make sure that only one radio button is selected by clearing previous selection. This logic can be implemented by saving last checked position and using it to uncheck the last checked radio button when user selects different radio button.
package com.example.srinu.stylesthemes;
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.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class OffersRecyclerViewAdapter extends
RecyclerView.Adapter<OffersRecyclerViewAdapter.ViewHolder> {
private List<OffersModel> offersList;
private Context context;
private int lastSelectedPosition = -1;
public OffersRecyclerViewAdapter(List<OffersModel> offersListIn
, Context ctx) {
offersList = offersListIn;
context = ctx;
}
@Override
public OffersRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.offer_item, parent, false);
OffersRecyclerViewAdapter.ViewHolder viewHolder =
new OffersRecyclerViewAdapter.ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(OffersRecyclerViewAdapter.ViewHolder holder,
int position) {
OffersModel offersModel = offersList.get(position);
holder.offerName.setText(offersModel.getOffer());
holder.offerAmount.setText("" + offersModel.getSavings());
//since only one radio button is allowed to be selected,
// this condition un-checks previous selections
holder.selectionState.setChecked(lastSelectedPosition == position);
}
@Override
public int getItemCount() {
return offersList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView offerName;
public TextView offerAmount;
public RadioButton selectionState;
public ViewHolder(View view) {
super(view);
offerName = (TextView) view.findViewById(R.id.offer_name);
offerAmount = (TextView) view.findViewById(R.id.offer_amount);
selectionState = (RadioButton) view.findViewById(R.id.offer_select);
selectionState.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lastSelectedPosition = getAdapterPosition();
notifyDataSetChanged();
Toast.makeText(OffersRecyclerViewAdapter.this.context,
"selected offer is " + offerName.getText(),
Toast.LENGTH_LONG).show();
}
});
}
}
}
RecyclerView is configured in onCreate method of Activity by setting adapter, layout manager and item decorator.
package com.example.srinu.stylesthemes;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class OffersActivity extends AppCompatActivity {
private RecyclerView offerRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_filter);
offerRecyclerView = (RecyclerView) findViewById(R.id.brands_lst);
LinearLayoutManager recyclerLayoutManager = new LinearLayoutManager(this);
offerRecyclerView.setLayoutManager(recyclerLayoutManager);
DividerItemDecoration dividerItemDecoration =
new DividerItemDecoration(offerRecyclerView.getContext(),
recyclerLayoutManager.getOrientation());
offerRecyclerView.addItemDecoration(dividerItemDecoration);
OffersRecyclerViewAdapter recyclerViewAdapter = new
OffersRecyclerViewAdapter(getBrands(),this);
offerRecyclerView.setAdapter(recyclerViewAdapter);
}
private List<OffersModel> getBrands(){
List<OffersModel> modelList = new ArrayList<OffersModel>();
modelList.add(new OffersModel("Get Upto 20% Off Clothing", 300));
modelList.add(new OffersModel("Free Smart Phone", 200));
modelList.add(new OffersModel("Pay $100 get big HD TV", 600));
modelList.add(new OffersModel("Get Upto 40% Off All", 500));
modelList.add(new OffersModel("Buy One Get One Free", 100));
modelList.add(new OffersModel("Pay $200 get Laptop", 1600));
modelList.add(new OffersModel("Get Upto 50% Off Electronics", 300));
modelList.add(new OffersModel("Free Movie Ticket", 400));
modelList.add(new OffersModel("Pay $100 Travel Europe", 700));
modelList.add(new OffersModel("Get Upto 27% Off Appliance", 600));
modelList.add(new OffersModel("Get Upto 44% Off Jewellery", 700));
modelList.add(new OffersModel("Free Coupons", 500));
modelList.add(new OffersModel("Pay $100 get Tablet", 600));
return modelList;
}
}