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
}
Related
I have a recycler view when clicked on the item VISIBLE hide seek bar for each item.
the issue is when clicked on a single item then VISIBLE multiple hides seek bar and also when scrolling up down auto show randomly seek bar in this recycler view. help me. Thanks
See in this screenshot
Adapter class
public class Adapter_Custom extends RecyclerView.Adapter<Adapter_Custom.ViewHolder> {
private Adapter_Custom.OnItemClickListener mListener;
public interface OnItemClickListener {
void onImageClick(int position,ImageView imageView,SeekBar seekBar);
void onSeekBarProgressChange(int position,String progress);
}
public void setOnItemClickListener(Adapter_Custom.OnItemClickListener listener) {
mListener = listener;
}
Context MyContext;
List<Model_main> modelList;
public Adapter_Custom(Context myContext, List<Model_main> modelList) {
MyContext = myContext;
this.modelList = modelList;
}
#NonNull
#Override
public Adapter_Custom.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(MyContext);
View view = inflater.inflate(R.layout.rv_item_custom, null, false);
return new Adapter_Custom.ViewHolder(view, mListener);
}
#Override
public void onBindViewHolder(#NonNull final Adapter_Custom.ViewHolder holder, int position) {
final Model_main model = modelList.get(position);
holder.textView3.setText(model.getName());
holder.sound_image.setImageResource(model.getImages());
}
#Override
public int getItemCount() {
return modelList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView textView3;
ImageView sound_image;
SeekBar seekBar;
public ViewHolder(#NonNull final View itemView, final Adapter_Custom.OnItemClickListener listener) {
super(itemView);
textView3 = itemView.findViewById(R.id.textView3);
sound_image = itemView.findViewById(R.id.sound_image);
seekBar = itemView.findViewById(R.id.seekBar);
sound_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onImageClick(position,sound_image,seekBar);
// Toast.makeText(MyContext, ""+position, Toast.LENGTH_SHORT).show();
}
}
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onSeekBarProgressChange(position,String.valueOf(seekBar.getProgress()));
}
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
}
}
ClickListner
adapter_custom1.setOnItemClickListener(new Adapter_Custom.OnItemClickListener() {
#Override
public void onImageClick(int position, ImageView imageView, SeekBar seekBar) {
Toast.makeText(getContext(), "" + position, Toast.LENGTH_SHORT).show();
rv.findViewHolderForAdapterPosition(position).itemView.findViewById(R.id.seekBar)
.setVisibility(isVisible()? View.VISIBLE : View.GONE);
// rv.findViewHolderForAdapterPosition(position).itemView.findViewById(R.id.seekBar).setVisibility(View.VISIBLE);
// rv.findViewHolderForAdapterPosition(position).itemView.findViewById(R.id.textView3).setVisibility(View.GONE);
if (custom_btn_div.getVisibility() == View.GONE) {
custom_btn_div.setVisibility(View.VISIBLE);
}
}
Problem: Setting view visibility or checkbox check or drawable an ImageView to one or some of a RecyclerView items (rows).
Solution: You need to negate the opposite to remaining Views; e.g. If you set visiblity of a row item view to VISIBLE, then you've to make sure to set it as GONE/INVISIBLE to the similar items of the other rows.
Reason: Because the RecyclerView, as indicates from its name, recycles views; so if it needs to hold 100 items; and the screen size can hold 10 items at a time; then with the next scroll of the RecyclerView it doesn't create those items from the scrach, but copies the data of the new items into their place holds; if the data (visibility) is not set, then it takes the old data.
#Override
public void onBindViewHolder(#NonNull final Adapter_Custom.ViewHolder holder, int position) {
final Model_main model = modelList.get(position);
holder.textView3.setText(model.getName());
holder.sound_image.setImageResource(model.getImages());
holder.seekBar.setVisibility(View.GONE);
}
I'm facing the next problem.
I have a RecyclerView with the Adapter, the items, etc.
What I need is: Select an item in the recycler, change the color of that item, and then I have to disable the rest of the other items. It's like a RadioButton list.
I select one and disable the others. If I select again the same item, enable all the list.
I already have the onClick Button listener. I need to know if I have to reload again de list, If I have to loop and disable item by item, etc.
Thanks
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Human> humans;
private HumanClick selectedHuman;
#Inject
public MyAdapter() {
}
public void init(List<Human> humanList, SelectedHumanClick humanClick){
this.humans = humanList;
this.humanClick = humanClick;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_Human, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
final Human human = Humans.get(position);
holder.bind(Humans.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedHumanClick.onSelectedHumanClick(Human);
}
});
}
#Override
public int getItemCount() {
return humans != null ? Humans.size() : 0;
}
public final class MyViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.text_view_human_name)
TextView textView;
#BindView(R.id.image_view_profile)
ImageView imageViewProf;
#BindView(R.id.image_view_radio_btn)
ImageView imageViewRB;
private boolean isChecked = false;
public MyViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(final Human Human) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
humanClick.onSelectedHumanClick(Human);
}
});
textView.setText(human.getName());
}
public void changeRBImage() {
if(!isChecked){
isChecked = true;
imageViewRB.setBackground(ContextCompat.getDrawable(imageViewRB.getContext(), R.drawable.selected));
}
else{
isChecked = false;
imageViewRB.setBackground(ContextCompat.getDrawable(imageViewRB.getContext(), R.drawable.not_selected));
}
}
}
My Recycler is defined inside a fragment here:
public class HumansFragment implenets HumanClick{
#BindView(R.id.recycler_humans)
RecyclerView humansRecyclerView;
#Inject
MyAdapter myAdapter;
.
.
.
public void loadHumans(List<Human> humans) {
myAdapter.init(Humans, this);
humansRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
humansRecyclerView.setAdapter(myAdapter);
}
#Override
public void humansClick(Human human) {
//TODO
}
}
I'm thinking in something like this, using setOnItemClickListener and check the position of the item clicked. The position is the index of the item clicked check the last event and new, if both are equal change color, if not dont do anything like disabling.
private ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
textView = (TextView)view.findViewById(android.R.id.text1);
}
#Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();
//go through each item if you have few items within recycler view
if(getLayoutPosition()==0){
//Do whatever you want here
}else if(getLayoutPosition()==1){
//Do whatever you want here
}else if(getLayoutPosition()==2){
}else if(getLayoutPosition()==3){
}else if(getLayoutPosition()==4){
}else if(getLayoutPosition()==5){
}
//or you can use For loop if you have long list of items. Use its length or size of the list as
for(int i = 0; i<exampleList.size(); i++){
}
}
}
Or something smaller
RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(context, recyclerView ,new
RecyclerItemClickListener.OnItemClickListener() {
#Override public void onItemClick(View view, int position) {
// do whatever
}
#Override public void onLongItemClick(View view, int position) {
// do whatever
}
})
);
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 having trouble removing items from RecyclerView. When I click on delete, the item is removed from RecyclerView, but comes back when I open the app again. I'm hoping it is just a minor issue that someone here can point out or direct me to what area to troubleshoot. The removeItem(String item) in bold is what I think is the issue. You can't see it in this post, but it is "not used".
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
private List<Grocery> mListData;
private SQLGroceryHelper helper;
RecyclerViewAdapter adapter;
//Adapter's Constructor//
public RecyclerViewAdapter(List<Grocery> mDataList) {
this.mListData = mDataList;
}
//Provide a reference to the views for each contact item//
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView rowItem;
ImageButton purchasedButton;
ImageButton deleteButton;
LinearLayout linearLayout;
public MyViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView.findViewById(R.id.recycler_row);
rowItem = (TextView) itemView.findViewById(R.id.item_field1);
purchasedButton = (ImageButton) itemView.findViewById(R.id.item_purchased);
deleteButton = (ImageButton) itemView.findViewById(R.id.delete_item);
}
}
//Inflate the view based on the viewtype provided//
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Create a new view by inflating the row item xml//
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row, parent, false);
//Set the view to the ViewHolder//
MyViewHolder holder = new MyViewHolder(row);
return holder;
}
//Display data at the specified position//
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.rowItem.setText(mListData.get(position).getTextItem());
holder.purchasedButton.setOnClickListener(new View.OnClickListener() {
//Ignore this click for now//
#Override
public void onClick(View v) {
removeItem(position);
}
});
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeItem(position);
}
});
}
public void **removeItem**(String item) {
int position = mListData.indexOf(item);
if (position != -1) {
mListData.remove(item);
notifyItemRemoved(position);
}
}
public void removeItem(int position) {
mListData.remove(position);
notifyItemRemoved(position);
}
#Override
public int getItemCount() {
if (mListData == null) {
return 0;
}
return mListData.size();
}
}
You are removing the data from local object, mListData I guess the original data object remains intact. Remove the data item from the original data object as well
Declare a interface
public interface AdapterCommunication{
void removeStringItem(int position);
}
then in your adapter
private AdapterCommunication mListener;
public void setOnClickListener(AdapterCommunication listener){
mListener = listener;
}
Then from your activity where you initialize the adapter
RecyclerViewAdapter adapter = new RecyclerViewAdapter(list);
adapter.setOnClickListener(new AdapterCommunication{
public void removeStringItem(int position){
list.remove(position);
adapter.notifyDataSetChanged();
}
});
In your adaper,
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.remove(position);
}
});
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));
}
}