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));
}
Related
I have two recycler views and both of them use the same custom adapter.
https://imgur.com/3WMGgiL - this is how the item from the recycler view looks like
What i want to do is, whenever the "Anuleaza rezervarea" button is clicked, i want to remove the item from the current recyclerview and add it to another recycler view
How can i do that? I'll leave my custom adapter code below. I really don't understand what to write in the on click listener.
public class RecyclerViewAdapterRezervare extends RecyclerView.Adapter<RecyclerViewAdapterRezervare.RecycleViewHolder> {
private List<Rezervare> rezervari;
private Context context;
private LayoutInflater inflater;
private String numeUtilizator;
private String status;
private Rezervare rezervare = new Rezervare();
private DatabaseReference reff;
public RecyclerViewAdapterRezervare(List<Rezervare> rezervari, Context context, String numeUtilizator) {
this.rezervari = rezervari;
this.context = context;
this.numeUtilizator = numeUtilizator;
this.inflater = LayoutInflater.from(context);
}
#NonNull
#Override
public RecycleViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.rezervari_layout, parent, false);
return new RecycleViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecycleViewHolder holder, int position) {
rezervare = rezervari.get(position);
holder.btn_anuleaza.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new AlertDialog.Builder(view.getContext()).setTitle("Anulare rezervare").setMessage("Sunteti sigur ca doriti anularea rezervarii?")
.setPositiveButton(R.string.da, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
holder.btn_anuleaza.setText(R.string.anulat);
holder.btn_anuleaza.setBackgroundColor(view.getResources().getColor(R.color.red));
}
}).setNegativeButton(R.string.nu, null).show();
}
});
}
#Override
public int getItemCount() {
return rezervari.size();
}
public static class RecycleViewHolder extends RecyclerView.ViewHolder {
public TextView tv_nume_teren;
public TextView tv_adresa_teren;
public TextView tv_ora;
public TextView tv_data;
public Button btn_anuleaza;
public Button btn_navigheaza;
public static boolean isCanceled;
public RecycleViewHolder(#NonNull View itemView) {
super(itemView);
tv_nume_teren = itemView.findViewById(R.id.tv_rezervare_nume_teren);
tv_adresa_teren = itemView.findViewById(R.id.tv_rezervare_adresa_teren);
btn_anuleaza = itemView.findViewById(R.id.btn_anuleaza);
btn_navigheaza = itemView.findViewById(R.id.btn_maps);
tv_ora = itemView.findViewById(R.id.tv_rezervare_ore);
tv_data = itemView.findViewById(R.id.tv_rezervare_data);
isCanceled = false;
if(isCanceled){
btn_anuleaza.setText(R.string.anulat);
btn_anuleaza.setBackgroundColor(itemView.getResources().getColor(R.color.red));
} else {
btn_anuleaza.setText(R.string.anuleaza_rezervare);
btn_anuleaza.setBackgroundColor(itemView.getResources().getColor(R.color.teal_700));
}
}
}
When i click on the "Anuleaza rezervare" button, the two buttons become red and unclickable, and i want to transfer the item to another recycler view. How can i do that? Thank you!
You can achieve this by calling,
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
on the first recyclerView and update the second by calling,
String newItem = "This is a new item.";
int updateIndex = 3; // Your index to insert new the item
data.set(updateIndex, newItem);
adapter.notifyItemChanged(updateIndex);
for the second recyclerView.
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.
I am developing an android app in which I use a RecyclerView. Suppose I have 6 items in my RecyclerView i.e. [A, B, C, D, E, F]. So how can I get the number of clicks on these items?
For example:
If an user open item B 4 times. How can I get the count = 4?
P.s. count should increase only when the user click on the same item.
First declare static count variables for each items
private static int aCount = 0;
Then inside your onBindViewHolder, pass a method after the button click along with your position id.
public void onBindViewHolder(ItemAdapter.ViewHolder holder, int position) {
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
thisWasClicked(position);
}
}
}
The method will be something like this
private void thisWasClicked(int position) {
if (position == 0) {
aCount++;
}
}
in holder
itemView.setOnClickListener(){
onClick(){
// count up
}
}
each item needs also an id to know, which item it is
I've made an example
CustomItem object
public class CustomItem {
private String item;
private int click;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public int getClick() {
return click;
}
public void setClick(int click) {
this.click = click;
}
}
CustomAdapter and CustomViewHolder for the recyclerview
public class CustomAdapter extends RecyclerView.Adapter{
private List<CustomItem> itemList;
public CustomAdapter(List<CustomItem> itemList){
this.itemList = itemList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.viewholder_generic, parent, false));;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//increase click count for the current item
itemList.get(holder.getAdapterPosition()).setClick(itemList.get(holder.getAdapterPosition()).getClick() + 1);
}
});
}
#Override
public int getItemCount() {
return itemList.size();
}
// Custom ViewHolder
public class CustomViewHolder extends RecyclerView.ViewHolder {
//add fields you need
public CustomViewHolder(View itemView) {
super(itemView);
}
}
}
You can create a Map<Integer, Integer> clicksMap = new HashMap<>() in your adapter
You should also pass an interface to your ViewHolder that acts as a click Listener. Something like.
public interface OnItemLick {
void onItemClick(int position, int id);
}
Then declare an instance of this interface in your adapter.
OnItemLick listener = new OnItemClick() {
void onItemClick(int position, int id) {
//you can either use the item position or an id (if you have an unique one for the items). I will show an example using the position.
int count;
if(clicksMap.contains(position)) {
count = clickMap.get(position);
count ++;
clickMap.put(position, count);
}else {
count ++;
clickMap.put(position, count); }
}
In the end you clicksMap will contain the click count for every position of the items in the recycler.
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));
}
}
I am trying to port my existing project to material design but am unable to understand the implementation of RecyclerView. My old code uses a ListView but I want GMail app like lists.
I have read tons of tutorials but most of them either skip the ItemDecoration part or the ClickListener part. Different tutorials have entirely different implementations and code varies to the point that I am unable to understand where to put what.
I am struggling in the following, which I compiled by reading various tutorials:
Adapter: My adapter code is the following:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private final Context mContext;
private List<String> mData1, mData2;
public MyAdapter(Context mContext, String[] data1,String[] data2) {
this.mContext = mContext;
if (data1 != null)
mData1 = new ArrayList<String>(Arrays.asList(data1));
else mData1 = new ArrayList<String>();
if (data2 != null)
mData2 = new ArrayList<String>(Arrays.asList(data2));
else mData2 = new ArrayList<String>();
}
public void add(String s,int position) {
position = position == -1 ? getItemCount() : position;
mData1.add(position,s);
notifyItemInserted(position);
}
public void remove(int position){
if (position < getItemCount() ) {
mData1.remove(position);
notifyItemRemoved(position);
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
View itemView = inflater.inflate(R.layout.list_item,viewGroup,false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder myViewHolder, int position) {
myViewHolder.tv1.setText(mData1.get(position));
myViewHolder.tv2.setText(mData2.get(position));
myViewHolder.setClickListener(new MyViewHolder.ClickListener()
{
#Override
public void onClick(View v, int pos) {
Toast.makeText(mContext,"The selected position is: "+ pos,Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return mData1.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
protected TextView tv1;
protected TextView tv2;
ClickListener clickListener;
public MyViewHolder(View itemView) {
super(itemView);
tv1 = (TextView) itemView.findViewById(R.id.txt1);
tv2 = (TextView) itemView.findViewById(R.id.txt2);
}
#Override
public void onClick(View v) {
}
public void onClick(View v, int pos)
{
clickListener.onClick(v,getPosition());
}
public void setClickListener(ClickListener clickListener)
{
this.clickListener = clickListener;
}
public interface ClickListener
{
public void onClick(View v,int pos);
}
}
}
The ItemDecoration is copied from here: https://gist.github.com/alexfu/0f464fc3742f134ccd1e. But do I really need such a large class just to put simple dividers between list items? What if I wanted to implement the code on my own?
I still cannot figure out the OnClickListener. For a start, the I want a simple OnClickListener just like ListView.OnClickListener. The current OnClickListener was compiled from a tutorial but does not work.
Full code here: https://github.com/pauldmps/MaterialDesign/
RecyclerView Adapter Example:
Adapter issue can be solved using below code:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>
{
private final Context mContext;
private List<String> mData1, mData2;
public MyAdapter(Context mContext, String[] data1, String[] data2) {
this.mContext = mContext;
if (data1 != null)
mData1 = new ArrayList<String>(Arrays.asList(data1));
else
mData1 = new ArrayList<String>();
if (data2 != null)
mData2 = new ArrayList<String>(Arrays.asList(data2));
else
mData2 = new ArrayList<String>();
}
public void add(String s, int position) {
position = position == -1 ? getItemCount() : position;
mData1.add(position, s);
notifyItemInserted(position);
}
public void remove(int position) {
if (position < getItemCount()) {
mData1.remove(position);
notifyItemRemoved(position);
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
View itemView = inflater.inflate(R.layout.list_item, viewGroup, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder myViewHolder, final int position) {
myViewHolder.tv1.setText(mData1.get(position));
myViewHolder.tv2.setText(mData2.get(position));
myViewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
clickListener.onClick(v, position);
}
});
}
#Override
public int getItemCount() {
return mData1.size();
}
ClickListener clickListener;
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
public interface ClickListener {
public void onClick(View v, int pos);
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
protected TextView tv1;
protected TextView tv2;
public MyViewHolder(View itemView) {
super(itemView);
tv1 = (TextView) itemView.findViewById(R.id.txt1);
tv2 = (TextView) itemView.findViewById(R.id.txt2);
}
}
}
Usage is as below:
MyAdapter adapter=....;
adapter.setClickListener(new ClickListener() {
#Override
public void onClick(View v, int pos) {
// do whatever you want
}
});
There is not any Simple way to do that. But i would suggest you one workaround for this. Add below view as a divider at the bottom inside your list_item.xml.
<View
android:layout_width="wrap_content"
android:layout_height="0.5dip"
android:background="#color/light_gray"/>
Item click listener is also resolved in point no. 1 above.
I hope this would help you.
Here is example for Simple Implementation of RecyclerView using a Simple Library
Add this line in build.gradle
implementation 'com.hereshem.lib:awesomelib:2.0.1'
Create RecyclerView Layout in Activity with
<com.hereshem.lib.recycler.MyRecyclerView
android:id="#+id/recycler"
app:layoutManager="LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Create a ViewHolder by passing the class it suppports
public static class EVHolder extends MyViewHolder<Events> {
TextView date, title, summary;
public EVHolder(View v) {
super(v);
date = v.findViewById(R.id.date);
title = v.findViewById(R.id.title);
summary = v.findViewById(R.id.summary);
}
#Override
public void bindView(Events c) {
date.setText(c.date);
title.setText(c.title);
summary.setText(c.summary);
}
}
Create Items List variable and adapters with very few lines
List<Events> items = new ArrayList<>();
MyRecyclerView recycler = findViewById(R.id.recycler);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event);
recycler.setAdapter(adapter);
ClickListener can be added with folllowing line
recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() {
#Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show();
}
});
More example can be found here
Hope this helps :)