RecyclerView Drawer - Set Selection - android

I am trying to code my own recyclerview slector algorithm. So far, I successfully managed to code that partially except handling the first selection. Basically I want to set background as blue for selected item, white elsewhere (same as ListView's setSelection).
So, the idea is:
Set Blue background for the first element in Adapter's onCreateViewHolder method.
In ActivityMain, define an intance View variable navMenuSelection to store current selection
In recyclerView's onclick listener, set the background of clicked view to blue, background of navMenuSelection as white, and update navMenuSelection to clicked view
All is working except:
1. Can't initialize navMenuSelection with the first view. Tried to use mDrawerLayout.getChildAt(0) at onPostCreate method, but returns null
How to pass the view navMenuSelection in savedInstanceState bundle?
Any idea will be highly appreciated.
public class ActivityMain extends AppCompatActivity {
private View navMenuSelection = null; // Select current view
protected void onCreate(Bundle savedInstanceState) {
// ALL THE CODES TO DEFINE RECYCLERVIEW
mRecyclerView.addOnItemTouchListener(new RecycleTouchListener(this, new ClickListner() {
#Override
public void onClick(View view, int position) {
if(view != navMenuSelection){
setNavItemSelected(view);
removeNavItemSelected(navMenuSelection);
navMenuSelection = view;
mDrawerLayout.closeDrawers();
}
}
}));
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
navMenuSelection = mDrawerLayout.getChildAt(0);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState){
//savedInstanceState.put???("currselection", navMenuSelection); // HOW TO DO THAT
super.onSaveInstanceState(savedInstanceState);
}
public void setNavItemSelected(View v){
if(v!= null) {
v.setBackgroundColor(R.color.BLUE));
}
}
public void removeNavItemSelected(View v){
if(v!= null) {
v.setBackgroundColor(R.color.WHITE));
}
}
}
Adapter Class (after moving onClick event to adapter)
public class NavDrawerAdapter extends RecyclerView.Adapter<NavDrawerAdapter.ViewHolder> {
private String[] mNavTitles; // stores title
private int[] mIcons; // stores icon
private Context context;
private int oldpostion = 0;
public NavDrawerAdapter(Context context, String Titles[], int[] Icons){
this.context = context;
mNavTitles = Titles;
mIcons = Icons;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
public ViewHolder (View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.title);
imageView = (ImageView) itemView.findViewById(R.id.icon);
}
}
#Override
public NavDrawerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.navdrawer_item,parent,false);
return new ViewHolder(v,viewType);
}
#Override
public void onBindViewHolder(NavDrawerAdapter.ViewHolder holder, final int position) {
holder.textView.setText(mNavTitles[position]);
holder.imageView.setImageResource(mIcons[position]);
if(position == 0) {
setNavItemSelected(holder.itemView);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(position != oldpostion){
setNavItemSelected(v);
//removeNavItemSelected(OLD VIEW);
oldpostion = position;
}
}
});
}
#Override
public int getItemCount() {
return mNavTitles.length;
}
#Override
public int getItemViewType(int position) {
return 1;
}
public void setNavItemSelected(View v){
if(v!= null) {
v.setBackgroundColor(context.getResources().getColor(R.color.navdrawer_item_selected_bg));
TextView tview = (TextView) v.findViewById(R.id.title);
tview.setTextColor(context.getResources().getColor(R.color.navdrawer_item_selected_text));
}
}
public void removeNavItemSelected(View v){
if(v!= null) {
v.setBackgroundResource(R.drawable.list_selector_nav_drawer);
TextView tview = (TextView) v.findViewById(R.id.title);
tview.setTextColor(context.getResources().getColorStateList(R.color.list_selector_nav_drawer_text));
}
}
}

As for your questions:
To get a view you need in the RecyclerView you can use mRecyclerView.findViewHolderForAdapterPosition(position).
I may be wrong but I think you only need to save the position of the view, not the view itself, which is just int.
Another pattern, I used before, is adding a boolean array to your RecyclerView.Adapter that saves the info about what view(s) (associated with a position in your data collection) should be activated in the moment. Based on this array I was changing background of views in onBindViewHolder().
Your current solution is ok if the recycler view is short enough to be seen on a single screen. But as soon as it starts recycling its old viewholders you'll get "selected" background reused as well on not selected views - all because you remembered views, rather than data positions connected to them.
EDIT
I'll put here some relevant code from the adapter to illustrate my idea on implementation. In my approach I used a state list drawable with "selected" background for the activated state, but you can do all the same by manually setting the background.
public class RecyclerAdapter
extends RecyclerView.Adapter<RecyclerAdapter.YourViewHolder> {
private final List<...> data;
private final RecyclerAdapterCallbacks listener; //e.g. for activity callbacks
private final List<Boolean> activation;
public RecyclerAdapter(List<...> data, RecyclerAdapterCallbacks listener) {
this.data = data;
this.listener = listener;
this.activation = new ArrayList<>(data.size());
fillActivationList();
}
private void fillActivationList() {
int size = data.size();
for (int i = 0; i < size; i++) activation.add(false);
}
//------YourViewHolder implementation here------
public interface RecyclerAdapterCallbacks { //Callbacks interface if needed
void onRowSelected(... dataPiece);
void onRowDeselected();
}
#Override
public WordsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//your code
}
#Override
public void onBindViewHolder(YourViewHolder holder, final int position) {
holder.field.setText(data.get(position).getString());
holder.itemView.setActivated(activation.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Boolean previousState = activation.get(position);
deactivateAll();
activation.set(position, !previousState);
notifyDataSetChanged();
if (!previousState) {
listener.onRowSelected(data.get(position));
} else {
listener.onRowDeselected();
}
}
});
}
private void deactivateAll() {
Collections.fill(activation, false);
}
#Override
public int getItemCount() {
return data.size();
}
public void clearResults() {
notifyItemRangeRemoved(0, data.size());
data.clear();
activation.clear();
}
public void add(Word item) {
data.add(item);
notifyItemInserted(data.size() - 1);
activation.add(false);
}

Since you are already using array to pass your icon and title, let's add another array to save your current selection
private boolean isSelected[] = {true, false, false, false, false}; //make sure that the length of this array matches the length of navtitles and navicon. set the first element to true since you want the first item to be selected by default. you can declare this directly on the adapter if this is static
or you can pass it as a parameter
private boolean isSelected[];
public NavDrawerAdapter(Context context, String Titles[], int[] Icons, boolean[] isSelected){
this.context = context;
mNavTitles = Titles;
mIcons = Icons;
this.isSelected = isSelected;
}
....
#Override
public void onBindViewHolder(NavDrawerAdapter.ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i < isSelected.length(); i++){
if (i==position){
isSelected[position]=true;
else
isSelected[position]=false;
}
notifyDataSetChanged();
}
});
if (isSelected[position]==true){
//execute your codes here
}else{
//execute your codes here
}
}
just try to debug if there's any error or typo. i did not use any code editor for this so there may be some error

To make it easier for you, I suggest just adding the layout in your viewholder so you can just change the background of the layout. not the cleanest method but this one should do the trick for you
public class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView;
LinearLayout layout; //whatever layout your using, just an example
public ViewHolder (View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.title);
imageView = (ImageView) itemView.findViewById(R.id.icon);
layout = (LinearLayout) itemView.findViewById(R.id.layout);
}
}
...
#Override
public void onBindViewHolder(NavDrawerAdapter.ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i < isSelected.length(); i++){
if (i==position){
isSelected[position]=true;
else
isSelected[position]=false;
}
notifyDataSetChanged();
}
});
if (isSelected[position]==true){
//execute your codes here
holder.layout.setBackgroundResource(R.drawable.list_selector_nav_drawer);
holder.textView.setTextColor(context.getResources().getColorStateList(R.color.list_selector_nav_drawer_text));
}else{
//execute your codes here
holder.layout.setBackgroundResource(R.drawable.list_selector_nav_drawer);
holder.textView.setTextColor(context.getResources().getColorStateList(R.color.list_selector_nav_drawer_text));
}
}

Related

Recyclerview single item selection not working correctly

I've implemented a recyclerview with staggered gridLayout containing about 31 items in the arrayList, recyclerview is working correctly, but I faced issue relating to single item selection.
When I select the value till "26" as shown in figure, its working fine
But, when I select the value after "26", the values from top most item are also selected, as shown in this next figure.
I require to only select one item at a time.
I've implemented the following code in my adapter class
public class DialogAdapter extends
RecyclerView.Adapter<DialogAdapter.DialogHolder>
{
// components
public Context context;
public ArrayList<AlertDialogModel> dialogArrayList = new
ArrayList<AlertDialogModel>();
private final ArrayList<Integer> selected = new ArrayList<>();
private int lastCheckedPosition = -1;
public Interface interface;
// parameterized constructor
public DialogAdapter(Context context, ArrayList<AlertDialogModel>
dialogArrayList,Interface interface)
{
this.context = context;
this.dialogArrayList = dialogArrayList;
this.interface = interface;
}
#NonNull
#Override
public DialogHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_cardview,parent,false);
DialogHolder dialogHolder = new DialogHolder(view);
return dialogHolder;
}
#Override
public void onBindViewHolder(#NonNull final DialogHolder holder, final int position)
{
final AlertDialogModel alertDialogModel = dialogArrayList.get(position);
holder.textView.setText(alertDialogModel.getDisplayValue());
if(lastCheckedPosition == position)
{
holder.textView.setTextColor(context.getResources().getColor(R.color.white));
holder.textView.setBackground(context.getResources().getDrawable(R.drawable.circular_shape_selection));
}
else
{
}
holder.textView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
lastCheckedPosition = position;
notifyDataSetChanged();
holder.textView.setTextColor(context.getResources().getColor(R.color.white));
holder.textView.setBackground(context.getResources().getDrawable(R.drawable.circular_shape_selection));
interface.getSelectedValue(alertDialogModel.getDisplayValue());
}
});
}
#Override
public int getItemCount()
{
return dialogArrayList.size();
}
public static class DialogHolder extends RecyclerView.ViewHolder
{
public TextView textView;
public DialogHolder(View itemView)
{
super(itemView);
textView = (TextView)itemView.findViewById(R.id.textView);
}
}
}
Can anyone relate my code and identify the issue ?
holder.textView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
lastCheckedPosition = position;
notifyDataSetChanged();
holder.textView.setTextColor(context.getResources().getColor(R.color.white));
holder.textView.setBackground(context.getResources().getDrawable(R.drawable.circular_shape_selection));
interface.getSelectedValue(alertDialogModel.getDisplayValue());
//below line is important to remove previous selected position from the variable
lastCheckedPosition = -1;
}
});
you should put the text view to the original state:
if(lastCheckedPosition == position)
{
holder.textView.setTextColor(context.getResources().getColor(R.color.white));
holder.textView.setBackground(context.getResources().getDrawable(R.drawable.circular_shape_selection));
}
else
{
holder.textView.setTextColor(context.getResources().getColor(R.color.transparent));
holder.textView.setBackground(null));
}

RecyclerView get View by position

I have a RecyclerView and each CardView contains a TextView and an ImageView. Whenever I click an item, I want to set the image visibility to VISIBLE and to set the previous clicked item image's visibility to INVISIBLE.
This is my Adapter class :
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder>{
private Context context;
private List<Category> lista;
private LayoutInflater layoutInflater;
private IncomeCategoryActivity activity;
private static final int CATEGORY_REQUEST=6;
private static final int ITEM_EDIT=1;
private static final int ITEM_DELETE=2;
private static final int EDIT_REQUEST=7;
private int current_pos=-1;
public CategoryAdapter(List<Category> lista, Context context, IncomeCategoryActivity activity) {
this.context = context;
this.lista = lista;
this.activity=activity;
layoutInflater=LayoutInflater.from(context);
}
#Override
public CategoryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=layoutInflater.inflate(R.layout.category_layout, parent, false);
ViewHolder viewHolder=new ViewHolder(view, activity);
return viewHolder;
}
#Override
public void onBindViewHolder(CategoryAdapter.ViewHolder holder, int position) {
holder.imageView.setImageURI(lista.get(position).getUri());
holder.textView.setText(lista.get(position).getCategory());
holder.position = position;
holder.category=lista.get(position);
if(holder.category.isChecked()==true){
holder.imageViewCheck.setVisibility(View.VISIBLE);
current_pos=position;
} else {
holder.imageViewCheck.setVisibility(View.INVISIBLE);
}
}
#Override
public int getItemCount() {
return lista.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener{
public ImageView imageView;
public TextView textView;
public ImageView imageViewCheck;
public int position;
public Category category;
public IncomeCategoryActivity activity;
public ViewHolder(View itemView, IncomeCategoryActivity activity) {
super(itemView);
this.activity=activity;
imageView=itemView.findViewById(R.id.customCategoryImageView);
textView=itemView.findViewById(R.id.customCategoryTextView);
imageViewCheck=itemView.findViewById(R.id.customCheckImageView);
itemView.setOnClickListener(this);
itemView.setOnCreateContextMenuListener(this);
}
#Override
public void onClick(View v) {
String aux=textView.getText().toString();
if(aux=="CATEGORIE NOUĂ"){
Intent intent=new Intent(context, CustomIncomeActivity.class);
activity.startActivityForResult(intent, CATEGORY_REQUEST);
}
else{
imageViewCheck.setVisibility(View.VISIBLE);
int pozitie_check=getLayoutPosition();
Intent intent=new Intent(context, AddIncomeActivity.class);
intent.putExtra("categorie_venit", aux);
intent.putExtra("position_check", pozitie_check);
activity.setResult(Activity.RESULT_OK, intent);
activity.finish();
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle("Selectează acțiunea");
MenuItem edit=menu.add(0, ITEM_EDIT, 0, "Modifică");
MenuItem delete=menu.add(0, ITEM_DELETE, 0, "Șterge");
edit.setOnMenuItemClickListener(this);
delete.setOnMenuItemClickListener(this);
}
#Override
public boolean onMenuItemClick(MenuItem item) {
int position=getLayoutPosition();
if (item.getGroupId() == 0) {
if(item.getItemId()==ITEM_EDIT){
Category category=lista.get(position);
Intent intent=new Intent(activity, CustomIncomeActivity.class);
intent.putExtra("edit_icon", category.getUri());
intent.putExtra("edit_category", category.getCategory());
intent.putExtra("list_position", position);
activity.startActivityForResult(intent, EDIT_REQUEST);
}
else if(item.getItemId()==ITEM_DELETE){
lista.remove(position);
notifyDataSetChanged();
}
}
return true;
}
At this moment, whenever I click an item, there are two images VISIBLE on the RecyclerView: the clicked item's image and the previous clicked item's image. I think I need to get the previous View by its position and to manually set the visibility to INVISIBLE.
recycleView.getChildCount() and recycleView_parent.getChildAt() only gives the Adapter items which is shows only screen .
that means if your list has 200 items and the only 5 items shows on screen so we can find only 5 item with the help of recycleView
i am using one simple trick to solve the issue.
You can define Hashmap which hold your holder objects
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
ArrayList<Model> dataList;
Context context;
HashMap<Integer,ViewHolder> holderlist;
public MyAdapter(ArrayList<Model> dataList, Context context) {
this.context = context;
this.dataList = dataList;
holderlist = new HashMap<>();
}
And after that to save the holder in Hashmap
public void onBindViewHolder(final ViewHolder holder, final int position) {
if(!holderlist.containsKey(position)){
holderlist.put(position,holder);
}
Create a method in Adapter.
public MyListAdapter.ViewHolder getViewByPosition(int position) {
return holderlist.get(position);
}
Call this method from your Activity or whenever you want.
for (int i = 0; i < datalList.size(); i++) {
MyAdapter.ViewHolder holder = ((MyAdapter)recycleView.getAdapter()).getViewByPosition(i);
View view = holder.itemView;
TextView tv = view.findViewById(R.id.tv);
}
I have created the demo you can refer it and implement for single selection
recyclerView.setAdapter(new RecyclerView.Adapter() {
int selected_position = -1;
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(
R.layout.row_color_list,parent,false)) {
#Override
public String toString() {
return super.toString();
}
};
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
ImageView imageView = holder.itemView.findViewById(R.id.image);
if(selected_position == position){
imageView.setVisibility(View.VISIBLE);
}else {
imageView.setVisibility(View.GONE);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selected_position != holder.getAdapterPosition()){
selected_position = holder.getAdapterPosition();
notifyDataSetChanged();
}
}
});
}
#Override
public int getItemCount() {
return 20;
}
});
You can do as following:
1) Declare a global variable:
private int selectedPos = -100; // Put any irrelevant number you want
2) Set selected position onClick() :
#Override
public void onClick(View v) {
selectedPos = getAdapterPosition();
}
3) Check selected postion and assign visibility inside onBindViewHolder():
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
if(position == selectedPos){
holder.imageViewCheck.setVisibility(View.VISIBLE);
} else {
holder.imageViewCheck.setVisibility(View.INVISIBLE);
}
}
Try this code..
add this code into adapter class for handling click event..
OnItemClick onItemClick;
public void setOnItemClick(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public interface OnItemClick {
void getPosition(String data); //pass any data to shared it.
}
after bind method..
#Override
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
// below code handle click event on recycler view item.
final String str=mStringList.get(position); // here your boject
if(holder.category.isChecked()==true){
holder.imageViewCheck.setVisibility(View.VISIBLE);
current_pos=position;
} else {
holder.imageViewCheck.setVisibility(View.INVISIBLE);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.getPosition(str); // pass your data.
}
});
}
after bind adapter into recycler view it means adapter not null then called below code..
adpater.setOnItemClick(new RecyclerViewAdpater.OnItemClick() {
#Override
public void getPosition(String data) {
// hear update your value for check into if condition.
data="sdfsdf";
adpater.notifyDataSetChanged();
}
});
and also read comments and also try to make custon class and access that object value and update after click it..
this code only how to handle click event into recycler view.

How to handle the recyclerview's items view inside activity?

In my app's recyclerview, each item have Play/Pause button to start/stop the media player. There are many events like downloading progress, play and stop the music. I'm going handle the events and update the UI immediately with broadcast receiver or in another way.
I do not know ho to access play or pause button in the activity.
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, #SuppressLint("RecyclerView") final int position) {
holder.downloading.setVisibility(View.INVISIBLE);
holder.equalizer.setVisibility(View.INVISIBLE);
holder.btnPlay.setVisibility(View.VISIBLE);
holder.btnPause.setVisibility(View.INVISIBLE);
}
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private ImageButton btnPlay, btnPause;
TextView title, id;
private ImageView trackImage, downloaded;
private GifImageView equalizer, downloading;
private CardView cardView;
public MyViewHolder(View itemView) {
super(itemView);
equalizer = itemView.findViewById(R.id.eq);
downloading = itemView.findViewById(R.id.loading);
btnPlay = itemView.findViewById(R.id.play);
btnPause = itemView.findViewById(R.id.pause);
btnPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyOnClickListener.playOnClick(v, getAdapterPosition());
}
});
btnPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyOnClickListener.pauseOnClick(v, getAdapterPosition());
}
});
}
and inside activity, here how i can access to btnPlay, btnPause, ,... to set them visible or invisible in specefic times:
adapter = new Adapter(tracks, this, new Adapter.MyAdapterListener() {
#Override
public void playOnClick(View v, int position) {
if (//true) {
adapter.notifyItemChanged(currentItem, //?);
}
// hide some views in recyclerview's item and show some others
} else {
//...
}
}
update:
for (int i = 0; i < tracks.size(); i++) {
Track track = tracks.get(i);
if (track.getPlayStatus()) {
track.setPlayStatus(false);
//tell the RecyclerView this data position has changes
adapter.notifyItemChanged(i);
break;
}
}
Track track = tracks.get(position);
track.setPlayStatus(true);
adapter.notifyItemChanged(position);
and onBindViewHolder:
if (track.getPlayStatus()) {
holder.btnPlay.setVisibility(View.INVISIBLE);
holder.btnPause.setVisibility(View.VISIBLE);
//other sets you need
} else {
holder.btnPlay.setVisibility(View.VISIBLE);
holder.btnPause.setVisibility(View.INVISIBLE); }
You should keep track of current playing position to fix this.
The trick is to refresh both the currently playing view as well as new clicked view
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
private int currentPlayingPosition = -1;
private MyOnClickListener mMyOnClickListener;
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// return viewholder
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if (position == currentPlayingPosition) {
holder.btnPlay.setVisibility(View.GONE);
holder.btnPause.setVisibility(View.VISIBLE);
} else {
holder.btnPlay.setVisibility(View.GONE);
holder.btnPause.setVisibility(View.VISIBLE);
}
// other bindings
}
#Override
public int getItemCount() {
// return size
}
public void setMyOnClickListener(MyOnClickListener myOnClickListener) {
mMyOnClickListener = myOnClickListener;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private ImageButton btnPlay, btnPause;
public MyViewHolder(View itemView) {
super(itemView);
// bind views
btnPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
int prev = currentPlayingPosition;
currentPlayingPosition = position;
if (prev >= 0)
notifyItemChanged(prev); // refresh previously playing view
notifyItemChanged(currentPlayingPosition);
mMyOnClickListener.playOnClick(v, position);
}
});
btnPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
notifyItemChanged(position);
currentPlayingPosition = -1;
mMyOnClickListener.pauseOnClick(v, position);
}
});
}
}
private interface MyOnClickListener {
void playOnClick(View v, int position);
void pauseOnClick(View v, int position);
}
}
You don't need to pass anything to your Activity if all you need is to change items of a specific row.
Let's say your list item is clicked for playing. Then, you just set the corresponding isPlaying flag(please add it if it's not there yet) of your data item to true as below and notify the adapter there a change:
#Override
public void playOnClick(View v, int position) {
// reset playing state for a previous track if only one item can be played at a time
for (int i = 0; i < trackList.size(); i++) {
Track track = trackList.get(i);
if (track.isPlaying()) {
track.setIsPlaying(false);
//tell the RecyclerView this data position has changes
adapter.notifyItemChanged(i);
break;
}
}
Track track = trackList.get(position);
track.setIsPlaying(true);
//initiate the RecyclerView redrawal
adapter.notifyItemChanged(position);
}
Your pauseOnClick could be:
#Override
public void pauseOnClick(View v, int position) {
Track track = trackList.get(position);
track.setIsPlaying(false);
//initiate the RecyclerView redrawal
adapter.notifyItemChanged(position);
}
In your onBindViewHolder you change the item visibility based on the adapter data you're passing:
#Override
public void onBindViewHolder(#NonNull Wkdapter.Holder holder, int position) {
Track track = trackListList.get(position);
if (track.isPlaying()) {
holder.btnPlay.setVisibility(View.VISIBLE);
holder.btnPause.setVisibility(View.INVISIBLE);
//other sets you need
} else {
holder.btnPlay.setVisibility(View.INVISIBLE);
holder.btnPause.setVisibility(View.VISIBLE);
//your other inits
}
}
You can pass your widgets as arguments to your MyOnClickListener functions, like below:
MyOnClickListener.playOnClick(v, btnPlay, getAdapterPosition());
try something like this
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private CardView oneway_card, CardView;
private ImageView logo, arrow;
private Context context;
private List<Onwardflights> objectlist;
private TextView arrival, departure, duration, amount, flightcode, arr_text, stops, stops_text;
public ViewHolder(View itemView, Context context, List<Onwardflights> objectlist) {
super(itemView);
itemView.setOnClickListener(this);
this.context = context;
this.objectlist = objectlist;
*Initialize here*
logo = (ImageView) itemView.findViewById(R.id.oneway_logo);
arrival = (TextView) itemView.findViewById(R.id.oneway_arrtime);
}
Your onclick method
#Override
public void onClick(View view) {
int position = getAdapterPosition();
Log.i("Position", "Postion " + position + " is clicked");
oneway_card.setCardBackgroundColor(Color.parseColor("#E0FFFF"));
//your code
}

Button doesn't react at clicking in RecycleView

I have created a simple RecycleView component. Then create a new activity for that component. In one row I have a TextView and Button. What I want to do is to change something in object which was put into the excatly one row.
First I initialized the Button:
public class RecycleViewAllWashesActivity extends Activity {
private Button isFavorite;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.row_recycleview);
isFavorite = (Button) findViewById(R.id.addToFav);
isFavorite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.w("myApp", String.valueOf(v.getId()));
int id = v.getId();
}
});
}
}
The adapter of RecycleView looks like:
#Override
public MyAdapter.WashLocationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View view = inflater.inflate(R.layout.row_recycleview, parent, false);
// Return a new holder instance
WashLocationViewHolder viewHolder = new WashLocationViewHolder(view);
return viewHolder;
}
// Involves populating data into the item through holder
#Override
public void onBindViewHolder(MyAdapter.WashLocationViewHolder viewHolder, int position) {
// Get the data model based on position
WashLocation w = washLocations.get(position);
String info = w.getWashName();
// Set item views based on your views and data model
TextView textView = viewHolder.info;
textView.setText(info);
Integer fav = w.getFav();
Boolean favorite = fav == 1 ? true : false;
Button addToFav = viewHolder.favorite;
addToFav.setText(favorite == true ? "Usuń z ulubionych" : "Dodaj do ulubionych");
}
Questions:
How to get the object which was put into one row?
When I clicked the Button (code above) it doesn't react, even breakpoint which was set there doesn't react? -> the thing in console which I see while clicking the button is:
04-17 13:11:00.137 7671-7671/com.example.micha.locationtest D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
==============================
Update:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ItemHolder> {
private List<WashLocation> washLocations;
private OnItemClickListener onItemClickListener;
private LayoutInflater layoutInflater;
public MyAdapter(List<WashLocation> washLocations, Context context) {
layoutInflater = LayoutInflater.from(context);
this.washLocations = washLocations;
}
#Override
public MyAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = layoutInflater.inflate(R.layout.row_recycleview, parent, false);
return new ItemHolder(itemView, this);
}
#Override
public void onBindViewHolder(MyAdapter.ItemHolder holder, int position) {
// Get the data model based on position
WashLocation w = washLocations.get(position);
String info = w.getWashName();
// Set item views based on your views and data model
TextView textView = holder.info;
textView.setText(info);
Integer fav = w.getFav();
Boolean favorite = fav == 1 ? true : false;
Button addToFav = holder.favorite;
addToFav.setText(favorite == true ? "Usuń z ulubionych" : "Dodaj do ulubionych");
}
#Override
public int getItemCount() {
return washLocations.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
onItemClickListener = listener;
}
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public interface OnItemClickListener {
public void onItemClick(ItemHolder item, int position);
}
/* public void add(int location, String iName){
itemsName.add(location, iName);
notifyItemInserted(location);
}
public void remove(int location){
if(location >= itemsName.size())
return;
itemsName.remove(location);
notifyItemRemoved(location);
}*/
public static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private MyAdapter parent;
TextView textItemName;
public TextView info;
public Button favorite;
public ItemHolder(View itemView, MyAdapter parent) {
super(itemView);
itemView.setOnClickListener(this);
this.parent = parent;
info = (TextView) itemView.findViewById(R.id.textView);
favorite = (Button) itemView.findViewById(R.id.addToFav);
}
public void setItemName(CharSequence name) {
textItemName.setText(name);
}
public CharSequence getItemName() {
return textItemName.getText();
}
#Override
public void onClick(View v) {
final OnItemClickListener listener = parent.getOnItemClickListener();
if (listener != null) {
listener.onItemClick(this, getPosition());
}
}
}
}
The activity class:
final DataBaseHelper dataBaseHelper = new DataBaseHelper(getApplicationContext());
washLocations = dataBaseHelper.getWashLocation();
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mAdapter = new MyAdapter(washLocations, this);
mAdapter.setOnItemClickListener(this);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
#Override
public void onItemClick(MyAdapter.ItemHolder item, int position) {
Log.d("myApp", "fdsgfds");
}
In Recycle review you must set an onClickListener for the views explicitly.
It does not have any default methods to handle click events like the listview.
You need to set an Onclick listener for your button in your WashLocationViewHolder
You will receive a click event there. From the view holder, you can send the event back to your fragment or activity using an interface.
if you need further help regarding this, mention it in the comments. I will provide you some samples.
How to get the object which was put into one row?
To do this you can set the object as a Tag using the setTag(Object) method in the layout or the button for which you will be providing a click listener. Then you can get the object using the getTag() method from the view.
Hope this helps.

How to implement RecycerView With Items having Radio buttons with single choice mode

I need to show a recyclerview with single choice item. but Recyclerview doesn't have the choice mode.
Does any one know how to resolve this?
Thanks in advance.
Store the states of the checked items in a SparseBooleanArray with the position as key.As you change the state of the button,update it's status in the booleanArray and call notifyItemChanged(position).And in BindviewHolder(ViewHolder viewholder,int position) method load the state from booleanArray like viewholder.radioButton.setChecked(boolean.get(position)).Have a look at this for basic idea
You could use something like this, it stores position for selected item, you could add a bit more code to store the item itself if your adapter reorders itself
public class SingleChoiceAdapter extends RecyclerView.Adapter<SingleChoiceAdapter.ItemViewHolder> {
private static final int NO_POSITION = -1;
private static final String SELECTED_ITEM_POSITION = "SELECTED_ITEM_POSITION";
private final LayoutInflater inflater;
private final List<Item> items;
private int selectedItemPosition = NO_POSITION;
public SingleChoiceAdapter(Context context, Bundle savedInstanceState) {
inflater = LayoutInflater.from(context);
items = new ArrayList<>();
if (savedInstanceState != null) {
selectedItemPosition = savedInstanceState.getInt(SELECTED_ITEM_POSITION, NO_POSITION);
}
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = inflater.inflate(R.layout.item, parent, false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(final ItemViewHolder holder, int position) {
final Item item = items.get(position);
holder.textView.setText(item.name);
holder.textView.setBackgroundColor(position == selectedItemPosition
? Color.LTGRAY
: Color.TRANSPARENT);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateSelectedItem(holder.getAdapterPosition());
}
});
}
#Override
public int getItemCount() {
return items.size();
}
public void setItems(List<Item> items) {
this.items.clear();
this.items.addAll(items);
notifyDataSetChanged();
}
public Item getSelectedItem() {
if (selectedItemPosition == NO_POSITION) {
return null;
}
return items.get(selectedItemPosition);
}
public void onSaveInstanceState(Bundle outState) {
outState.putInt(SELECTED_ITEM_POSITION, selectedItemPosition);
}
private void updateSelectedItem(int newSelectedItemPosition) {
if (selectedItemPosition != NO_POSITION) {
notifyItemChanged(selectedItemPosition);
}
selectedItemPosition = newSelectedItemPosition;
notifyItemChanged(newSelectedItemPosition);
}
public static class ItemViewHolder extends RecyclerView.ViewHolder {
public final TextView textView;
public ItemViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text_view);
}
}
}
Displaying already checks-
You can maintain a boolean array of size of your list. On bind view handle the boolean(true/ false) logic, like setting check true/false of a radio button.
Handling new clicks-
Then on the onclick of the radio button, set the value of every array element to false and setting the current array position to true after that. Now call notifyDatatSetChanged().
You can even do it with just one single integer variable instead of maintaining an array which is costly in devices like android where space is a constraint.
So, just maintain a single integer variable, lets say int selectedPosition=-1 initially.
In onBind check if the position==selectedPosition, if true check the button else uncheck.
Whenever user checks/unchecks the button, just update the selectedPosition
Something like this,
if(selectedPosition==position)
selectedPosition=-1
else{
selectedPosition=position
notifyItemChanged(selectedPosition);
}
notifyItemChanged(position);
Please set the id for the position in onBindViewHolder then you can process action in this method too. Update data set and call notifyDataSetChanged
Here is my example code
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ItemObject itemObject = mDataset.get(position);
((ViewHolder)holder).mTextView.setText(itemObject.getTitle());
Button mButton = ((ViewHolder) holder).mButton;
mButton.setSelected(itemObject.isSelected());
if(itemObject.isSelected()){
((ViewHolder)holder).mTextView.setText("OK");
}
mButton.setTag(position);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateDatset((Integer) v.getTag());
}
});
}
In the updateDataset method, I update information of this dataset and call notifyDataSetChanged()
Good luck

Categories

Resources