I have made a note app and everything works fine. Just in RecyclerView List when I choose an item or items and in menu I click delete button I the note is not deleted. Although delete method works in another place.
Here's the method of delete button in menu :
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (item.getItemId() == R.id.delete_selected) {
for (NotePad notePad : notes) {
if (selectedIds.contains(notePad.getId())) {
database = new Database(this);
database.deleteNote(notePad.getId());
}
}
adapter.notifyDataSetChanged();
return true;
}
return false;
}
And method of delete note in my database class:
void deleteNote(long id) {
SQLiteDatabase database = this.getWritableDatabase();
database.delete(DATABASE_TABLE, ID + "=?", new String[] {String.valueOf(id)});
database.close();
}
I don't know how to relate id of selected note to my method cause deletNote method receives long value but my selectedId is List.
Thanks in advance.
UPDATED
I realized my code works find but it doesn't refresh the list and also goes back from ActionMode to Toolbar. I tried adapter.notifyDataSetChanged();
Use this adapter. I have used interface.
public class NotePadAdapter extends RecyclerView.Adapter < NotePadAdapter.ViewHolder > {
private Context context;
private LayoutInflater inflater;
private List < NotePad > notes;
private List < Long > selectedIds = new ArrayList < > ();
private NoteClickListener listener;
NotePadAdapter(Context context, NoteClickListener listener, List < NotePad > notes) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.notes = notes;
this.listener = listener;
}
public interface NoteClickListener {
public void onNoteClick(NotePad notePad);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.notes_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
String title = notes.get(position).getTitle();
String date = notes.get(position).getDate();
String time = notes.get(position).getTime();
holder.setOnClickListener() {
listener.onNoteClick(notes.get(position))
}
holder.noteTitle.setText(title);
holder.noteTitle.setText(title);
holder.noteDate.setText(date);
holder.noteTime.setText(time);
long id = notes.get(position).getId();
if (selectedIds.contains(id)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.rooView.setForeground(new ColorDrawable(ContextCompat.getColor(context, R.color.colorControlActivated)));
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.rooView.setForeground(new ColorDrawable(ContextCompat.getColor(context, android.R.color.transparent)));
}
}
}
#Override
public int getItemCount() {
return notes.size();
}
public NotePad getItem(int position) {
return notes.get(position);
}
public void setSelectedIds(List < Long > selectedIds) {
this.selectedIds = selectedIds;
notifyDataSetChanged();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView noteTitle, noteDate, noteTime;
ConstraintLayout rooView;
ViewHolder(#NonNull View itemView) {
super(itemView);
noteTitle = itemView.findViewById(R.id.note_title);
noteDate = itemView.findViewById(R.id.note_date);
noteTime = itemView.findViewById(R.id.note_time);
rooView = itemView.findViewById(R.id.root_view);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(v.getContext(), ContentActivity.class);
i.putExtra("ID", notes.get(getAdapterPosition()).getId());
v.getContext().startActivity(i);
}
});
}
}
}
In your activity/fragment where you are initiating this adapter pass this for the listener and implement the interface and whenever you click any item on the recyclerview then you will your whole NotePad object inside this function.
Related
I am working on an application where i have list of items in recyclerview on items i have a hear icon as wishlist the problem is when i click on the first item the last item automatically selected when i select the second item the second last got selected automatically. I dont know why this is happening?? please guide me
My RecyclerView Adapter
public class RecyclerviewAdapter extends RecyclerView.Adapter<RecyclerviewAdapter.Viewholder> {
ArrayList<RecyclerviewModel> datalist;
Context context;
public RecyclerviewAdapter(ArrayList<RecyclerviewModel> datalist, Context context) {
this.datalist = datalist;
this.context = context;
}
#NonNull
#Override
public Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View viewholder = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_item, parent , false);
return new Viewholder(viewholder);
}
#Override
public void onBindViewHolder(#NonNull Viewholder holder, int position)
{
holder.name.setText(datalist.get(position).getName());
holder.email.setText(datalist.get(position).getEmail());
holder.desc.setText(datalist.get(position).getDesc());
holder.book.setText(datalist.get(position).getBook());
//code for setting image-slider on home
holder.sliderAdapterExample = new SliderAdapterExample(context.getApplicationContext(), datalist.get(position).getImages());
holder.imageSlider.setSliderAdapter(holder.sliderAdapterExample);
final RecyclerviewModel datawish = datalist.get(position);
String wishName = datawish.getName();
String wishEmail = datawish.getEmail();
holder.wishlist.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
int pos = holder.getBindingAdapterPosition();
if(compoundButton.isChecked())
{
Toast.makeText(context, "item added to wishlist" + pos , Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "item removed to wishlist", Toast.LENGTH_SHORT).show();
}
}
});
}
#Override
public int getItemCount() {
return datalist.size();
}
public class Viewholder extends RecyclerView.ViewHolder{
TextView name, email, desc, book;
SliderView imageSlider;
SliderAdapterExample sliderAdapterExample;
CheckBox wishlist;
public Viewholder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.text_name);
email = itemView.findViewById(R.id.text_email);
desc = itemView.findViewById(R.id.text_desc);
book = itemView.findViewById(R.id.text_book);
wishlist = itemView.findViewById(R.id.wishlist_checkbox);
imageSlider = itemView.findViewById(R.id.imageView3);
}
}
}
i click on the first heart icon
the last one is automatically clicked
Why this happening? Because when you scroll recyclerview remove hidden items automatically. For ex: 0 will be remove when scroll down and 1 item will be 0, 2 item will be 1 and 3->2,4->3 like this. There are 2 ways fix this error:
1) Simple way, but this method freeze your app when data is big:
#Override
public void onBindViewHolder(#NonNull Viewholder holder, int position)
{
holder.setIsRecyclable(false);
}
2) If you want you use second method you must add unique_id to your arraylist each item:
public class RecyclerviewAdapter extends RecyclerView.Adapter<RecyclerviewAdapter.Viewholder> {
ArrayList<RecyclerviewModel> datalist;
Context context;
private ArrayList<String> checkedItems=new ArrayList<>();
public RecyclerviewAdapter(ArrayList<RecyclerviewModel> datalist, Context context) {
this.datalist = datalist;
this.context = context;
}
#NonNull
#Override
public Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View viewholder = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_item, parent , false);
return new Viewholder(viewholder);
}
#Override
public void onBindViewHolder(#NonNull Viewholder holder, int position)
{
int pos=holder.getAdapterPosition();
holder.name.setText(datalist.get(pos).getName());
holder.email.setText(datalist.get(pos).getEmail());
holder.desc.setText(datalist.get(pos).getDesc());
holder.book.setText(datalist.get(pos).getBook());
//code for setting image-slider on home
holder.sliderAdapterExample = new SliderAdapterExample(context.getApplicationContext(), datalist.get(pos).getImages());
holder.imageSlider.setSliderAdapter(holder.sliderAdapterExample);
final RecyclerviewModel datawish = datalist.get(pos);
String wishName = datawish.getName();
String wishEmail = datawish.getEmail();
holder.wishlist.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b){
checkedItems.add(datalist.get(pos).getUniqueId());
} else {
checkedItems.remove(datalist.get(pos).getUniqueId());
}
}
});
// Check your selection here
if(checkedItems.contains(datalist.get(pos).getUniqueId())){
holder.wishlist.setChecked(true);
} else {
holder.wishlist.setChecked(false);
}
}
#Override
public int getItemCount() {
return datalist.size();
}
public class Viewholder extends RecyclerView.ViewHolder{
TextView name, email, desc, book;
SliderView imageSlider;
SliderAdapterExample sliderAdapterExample;
CheckBox wishlist;
public Viewholder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.text_name);
email = itemView.findViewById(R.id.text_email);
desc = itemView.findViewById(R.id.text_desc);
book = itemView.findViewById(R.id.text_book);
wishlist = itemView.findViewById(R.id.wishlist_checkbox);
imageSlider = itemView.findViewById(R.id.imageView3);
}
}
}
When you call your Adapter in your Fragment or Activity, add this line before setAdapter()
recyclerView.setItemViewCacheSize(mData.size());
I built a simple quiz app with sqlite database
There is some quiz headers and into this quiz headers we have some questions that show by recycler view. All questions have one question title and 4 answers and one correct answer. user chooses the radio button answers and after that click on confirm button that is located as item at the bottom of recycler view.
I can catch the correct answer with a simple way and send it to the activity with an interface. But i want to show the correct and wrong answers with changing the radio buttons color but I can't create another method and change the view holder items because I can't access to the view holders outside of 'onBindViewHolder' method . I can handle this with another adapter . I mean I can create a fake adapter that just show answers . Is it a right way ?
This is my code. It's a little messy. Sorry about that
public class QuestionRecyclerAdapter extends RecyclerView.Adapter<QuestionRecyclerAdapter.ViewHolder> {
private Context context;
private List<QuestionHolder> questionHolders;
private OnQuestionAnswerSelect onQuestionAnswerSelect;
private OnConfirmButtonClicked onConfirmButtonClicked;
public QuestionRecyclerAdapter(Context context, List<QuestionHolder> questionHolders) {
this.context = context;
this.questionHolders = questionHolders;
}
public void setOnQuestionAnswerSelect(OnQuestionAnswerSelect onQuestionAnswerSelect) {
this.onQuestionAnswerSelect = onQuestionAnswerSelect;
}
public void setOnConfirmButtonClicked(OnConfirmButtonClicked onConfirmButtonClicked){
this.onConfirmButtonClicked = onConfirmButtonClicked;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView;
if (viewType == R.layout.question_item)
itemView = LayoutInflater.from(context).inflate(R.layout.question_item, parent, false);
else
itemView = LayoutInflater.from(context).inflate(R.layout.question_recycler_confirm_button, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if (position != questionHolders.size()) {
QuestionModel currentModel = questionHolders.get(position).getQuestionModel();
holder.txtQuestion.setText(currentModel.getTitle());
holder.rBtnAnswer1.setText(currentModel.getOption1());
holder.rBtnAnswer2.setText(currentModel.getOption2());
holder.rBtnAnswer3.setText(currentModel.getOption3());
holder.rBtnAnswer4.setText(currentModel.getOption4());
if (onQuestionAnswerSelect != null) {
holder.questionRadioGroup.setOnCheckedChangeListener((v, i) -> {
RadioButton rBtnSelected = holder.questionRadioGroup.findViewById(holder.questionRadioGroup.getCheckedRadioButtonId());
int selectedRadioIndex = holder.questionRadioGroup.indexOfChild(rBtnSelected) + 1;
if (selectedRadioIndex == questionHolders.get(position).getQuestionModel().getCorrectNumber()) {
onQuestionAnswerSelect.onAnswerSelected(questionHolders.get(position).get_id(), true);
} else {
onQuestionAnswerSelect.onAnswerSelected(questionHolders.get(position).get_id(), false);
}
});
}
}else {
holder.btnConfirm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (onConfirmButtonClicked != null)
onConfirmButtonClicked.onConfirmClicked();
}
});
}
}
#Override
public int getItemCount() {
return questionHolders.size() + 1;
}
#Override
public int getItemViewType(int position) {
return (position == questionHolders.size()) ? R.layout.question_recycler_confirm_button : R.layout.question_item;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtQuestion;
public RadioGroup questionRadioGroup;
public RadioButton rBtnAnswer1;
public RadioButton rBtnAnswer2;
public RadioButton rBtnAnswer3;
public RadioButton rBtnAnswer4;
public Button btnConfirm;
public ViewHolder(#NonNull View itemView) {
super(itemView);
txtQuestion = itemView.findViewById(R.id.txtQuestion);
questionRadioGroup = itemView.findViewById(R.id.questionRadioGroup);
rBtnAnswer1 = itemView.findViewById(R.id.rBtnAnswer1);
rBtnAnswer2 = itemView.findViewById(R.id.rBtnAnswer2);
rBtnAnswer3 = itemView.findViewById(R.id.rBtnAnswer3);
rBtnAnswer4 = itemView.findViewById(R.id.rBtnAnswer4);
btnConfirm = itemView.findViewById(R.id.btnConfirm);
}
}
}
public class QuizActivity extends AppCompatActivity {
RecyclerView questionRecyclerView ;
QuestionRecyclerAdapter adapter ;
QuestionDatabaseHelper questionDatabaseHelper ;
Map<Integer,Boolean> answeredRecords = new HashMap<>();
int score ;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
questionRecyclerView = findViewById(R.id.questionRecyclerView);
questionDatabaseHelper = new QuestionDatabaseHelper(this);
int selectedId = getIntent().getIntExtra(Constants.SELECTED_ID,0);
score = 0 ;
List<QuestionHolder> questionHolders = questionDatabaseHelper.getAllQuestionHoldersById(selectedId);
adapter = new QuestionRecyclerAdapter(this,questionHolders);
questionRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
questionRecyclerView.setAdapter(adapter);
adapter.setOnQuestionAnswerSelect(new OnQuestionAnswerSelect() {
#Override
public void onAnswerSelected(int questionNumber, boolean isCorrect) {
answeredRecords.put(questionNumber,isCorrect);
}
});
adapter.setOnConfirmButtonClicked(new OnConfirmButtonClicked() {
#Override
public void onConfirmClicked() {
score = 0 ;
for(Map.Entry<Integer,Boolean> item : answeredRecords.entrySet()){
if (item.getValue())
score++;
}
Log.e("THE SCORE IS ", String.valueOf(score));
}
});
}
private void displayRecords(){
for(Map.Entry<Integer,Boolean> item : answeredRecords.entrySet()){
Log.e("AAA",item.getKey() + " : " + item.getValue());
}
}
}
Make a function in adapter and send holder to activity by calling that function.
first make viewholder named holder1.
ViewHolder holder1;
then at the onBindViewHolder method add this:
holder1 = holder;
public ViewHolder getHolder(){
return holder1;
}
now you can use it in your Activity like this:
adapter.getHolder.rBtnAnswer1.setBackgroundColor(Color.parseColor("#FFFFFF")); //this is a example.
Hello I am trying to implement multi select in recycler view android for showing an icon when clicked on that particular view, I have tried the below code and is working fine for that particular position, however there are other several views that too are getting updated, so please check and let me know what am I missing
Here is my adapter code:
public class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
Context context;
ArrayList<String> alContactName, alContactEmail, alContactNumber;
ArrayList<Boolean> alFromLinkedIn;
int mergeFlag=0;
private static SparseBooleanArray selectedItems;
ArrayList<Integer> alSelectedPositions;
public ContactsAdapter(Context context, ArrayList<String> alContactName, ArrayList<String> alContactEmail, ArrayList<String> alContactNumber, ArrayList<Boolean> alisFromLinkedIn) {
//Include one more variable for checking type i.e linked in or normal contact
super();
this.context = context;
this.alContactName = alContactName;
this.alContactEmail = alContactEmail;
this.alContactNumber = alContactNumber;
this.alFromLinkedIn = alisFromLinkedIn;
alSelectedPositions=new ArrayList<>();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_merge_contact, parent, false);
return new ContactsHolder(view);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
try {
((ContactsHolder) holder).relMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
alSelectedPositions.add(position);
notifyDataSetChanged();
}
});
if(alSelectedPositions.get(position)==position){
((ContactsHolder) holder).imgMerge.setVisibility(View.VISIBLE);
}
else {
((ContactsHolder) holder).imgMerge.setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
check updated code. I have modified the #tahsinRupam code.
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
try {
((ContactsHolder) holder).relMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(alSelectedPositions.size>0)
{
for(int i=0;i<a1SelectedPositions.size;i++)
{
//if you want to cleasr previous details of array
if(a1SelectedPositions.contains(position))
alSelectedPositions.remove(position);
else
alSelectedPositions.add(position);
}
}
else
{
alSelectedPositions.add(position);
notifyDataSetChanged();
}
});
//update the position on scroll
for(int i=0;i<a1SelectedPositions.size;i++)
{
if(alSelectedPositions.get(i)==position){
((ContactsHolder)holder).imgMerge.setVisibility(View.VISIBLE);
}
else {
((ContactsHolder) holder).imgMerge.setVisibility(View.GONE);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Recently I had to implement a multi select RecyclerView, below I attached a simplified code snippet for a clean way to implement multi-select feature in RecyclerView:
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemHolder> implements IMultiSelectableList<Item> {
boolean selectionMode = false;
HashSet<Item> selectedItems;
ArrayList<Item> mItems;
public ItemAdapter(ArrayList<Item> Items) {
super();
selectedItems = new HashSet<>();
mItems = Items;
}
public void enterSelectionModeWithItem(int selectedItemPosition){
if(selectedItemPosition >= 0 && selectedItemPosition < mItems.size())
selectedItems.add(mItems.get(selectedItemPosition));
selectionMode = true;
notifyDataSetChanged();
}
public void clearSelectionMode() {
selectionMode = false;
selectedItems.clear();
notifyDataSetChanged();
}
public class ItemHolder extends RecyclerView.ViewHolder{
ImageView mImage;
public ItemHolder(View itemView) {
super(itemView);
mImage = itemView.findViewById(R.id.image);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
if(!selectionMode){
int selectedPosition = getAdapterPosition();
Item selectedItem = mItems.get(selectedPosition);
enterSelectionModeWithItem(selectedItem);
return true;
}
return false;
}
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int selectedPosition = getAdapterPosition();
Item selectedItem = mItems.get(selectedPosition);
//Capture Clicks in Selection Mode
if(selectionMode){
if(selectedItems.contains(selectedItem)){
selectedItems.remove(selectedItem);
mImage.setImageResource(R.drawable.ic_checkbox_blank_circle_outline_grey600_48dp);
} else {
selectedItems.add(selectedItem);
mImage.setImageResource(R.drawable.ic_checkbox_marked_circle_grey600_48dp);
}
}
}
});
}
public void setupView(Item item){
if(selectionMode){
if(selectedItems.contains(item)){
mImage.setImageResource(R.drawable.ic_checkbox_marked_circle_grey600_48dp);
} else {
mImage.setImageResource(R.drawable.ic_checkbox_blank_circle_outline_grey600_48dp);
}
}
}
#Override
public ItemAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_item, parent, false);
return new ItemHolder(view);
}
#Override
public void onBindViewHolder(ItemAdapter.ItemHolder holder, int position) {
holder.setupView(mItems.get(position));
}
#Override
public int getItemCount() {
return mItems != null ? mItems.size() : 0;
}
}
, I use an image to show selection like Gmail app but feel free to use whatever works for you (background color, font style, etc).
P.S: I designed a callback interface for a simple selection interactions, if it helps I can attach it too! Cheers!
You've to do some specific things:
Initialize an int type array (type can be different) and assign 0 value to all it's elements.
int[] selectedPos = null;
public ContactsAdapter(Context context, ArrayList<String> alContactName, ArrayList<String> alContactEmail, ArrayList<String> alContactNumber, ArrayList<Boolean> alisFromLinkedIn) {
//Include one more variable for checking type i.e linked in or normal contact
super();
this.context = context;
this.alContactName = alContactName;
this.alContactEmail = alContactEmail;
this.alContactNumber = alContactNumber;
this.alFromLinkedIn = alisFromLinkedIn;
alSelectedPositions=new ArrayList<>();
for(int i = 0 ; i < alContactName.size() ; i++)
selectedPos[i] = 0;
}
Store the selected positions in selectedPos.
Then, check if the position is selected and set visibility accordingly:
In onBindViewHolder() add the following code:
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
try {
((ContactsHolder) holder).relMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectedPos[position] = 1;
notifyDataSetChanged();
}
});
} catch (Exception e) {
e.printStackTrace();
}
// Checking if the position was selected
if(selectedPos[position] == 1)
((ContactsHolder) holder).imgMerge.setVisibility(View.VISIBLE);
else
((ContactsHolder) holder).imgMerge.setVisibility(View.GONE);
}
I have resolved my issue here is the code if it could help someone:
#Override
public ContactsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_merge_contact, parent, false);
final ContactsHolder holder = new ContactsHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (holder.getAdapterPosition() != RecyclerView.NO_POSITION) {
mSelectedItemPosition = holder.getAdapterPosition();
//notifyItemChanged(holder.getAdapterPosition());
notifyDataSetChanged();
}
}
});
return holder;
}
#Override
public void onBindViewHolder(ContactsHolder holder, int position) {
try {
if (mSelectedItemPosition == position) {
if (mergeFlag != 1) {
holder.imgMerge.setVisibility(View.VISIBLE);
mergeFlag = 1;
selectdParentId = contactsModels.get(position).alContactIdList;
} else{
//holder.relDone.setVisibility(View.GONE);
if (!selectdParentId.equals(contactsModels.get(position).alContactIdList)) {
holder.relDone.setVisibility(View.VISIBLE);
alChildId.add(contactsModels.get(position).alContactIdList);
} else {
holder.imgMerge.setVisibility(View.VISIBLE);
}
}
} else {
holder.imgMerge.setVisibility(View.GONE);
holder.relDone.setVisibility(View.GONE);
}
}
I'm trying to retrieve all the checkboxes from my RecyclerView in order to uncheck them. However, this error is shown. Below are the classes that LogCat points to.
java.lang.IllegalArgumentException: itemView may not be null
at android.support.v7.widget.RecyclerView$ViewHolder.<init>(RecyclerView.java:10314)
at br.com.ufrn.marceloaugusto.tasklist.adapter.ProdutoAdapter$ProdutosViewHolder.<init>(ProdutoAdapter.java:0)
at br.com.ufrn.marceloaugusto.tasklist.MainActivity.onOptionsItemSelected(MainActivity.java:93)
MainActivity.java
public class MainActivity extends BaseActivity {
//private SQLiteDatabase banco;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpToolbar();
if (savedInstanceState == null) {
FragmentProdutos frag = new FragmentProdutos();
getSupportFragmentManager().beginTransaction().add(R.id.container, frag).commit();
}
//FAB
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
snack(view, "Adicionar produto");
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_desmarkAll) {
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerView);
ProdutoAdapter.ProdutosViewHolder holder = null;
int id = 0;
for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
if (holder.checkBox.isChecked()) {
holder.checkBox.setChecked(false);
}
}
return true;
}
return super.onOptionsItemSelected(item);
}}
ProdutoAdapter.java
public class ProdutoAdapter extends RecyclerView.Adapter<ProdutoAdapter.ProdutosViewHolder> {
private final Context context;
private final List<Produto> produtos;
//Interface para expor os eventos de toque na lista
private ProdutoOnClickListener produtoOnClickListener;
private ProdutoOnCheckListener produtoOnCheckListener;
public ProdutoAdapter(Context context, List<Produto> produtos, ProdutoOnClickListener produtoOnClickListener, ProdutoOnCheckListener produtoOnCheckListener) {
this.context = context;
this.produtos = produtos;
this.produtoOnClickListener = produtoOnClickListener;
this.produtoOnCheckListener = produtoOnCheckListener;
}
#Override
public int getItemCount() {
return this.produtos != null ? this.produtos.size() : 0;
}
#Override
public ProdutosViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.adapter_produto, parent, false);
ProdutosViewHolder holder = new ProdutosViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(final ProdutosViewHolder holder, final int position) {
Produto p = produtos.get(position);
holder.tNome.setText(p.getNome());
//holder.tPreco.setText(String.valueOf(p.getPreco()));
if (produtoOnClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
produtoOnClickListener.onClickProduto(view, position);
}
});
}
if (produtoOnCheckListener != null) {
holder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
produtoOnCheckListener.onCheckProduto(view, position);
}
});
}
}
public interface ProdutoOnClickListener {
public void onClickProduto(View view, int idx);
}
public interface ProdutoOnCheckListener {
public void onCheckProduto(View view, int position);
}
public static class ProdutosViewHolder extends RecyclerView.ViewHolder {
public TextView tNome;
//public TextView tPreco;
CardView cardView;
public CheckBox checkBox;
public ProdutosViewHolder(View view) {
super(view);
tNome = (TextView) view.findViewById(R.id.nomeProduto);
//tPreco = (TextView) view.findViewById(R.id.precoProduto);
cardView = (CardView) view.findViewById(R.id.card_view);
checkBox = (CheckBox) view.findViewById(R.id.checkProduto);
}
}
}
Method getChildAt is method of ViewGroup, so recycler.getChildAt(i) will be null for you. In your case you should use produtos list, iterate over it and set its field associated to "checked" state to "false", invoke notifyDataSetChanged() method of your adapter and then onBindViewHolder() will automatically change holder's checkBox values.
So instead of
for (int i = 0; i < recycler.getAdapter().getItemCount(); i++) {
holder = new ProdutoAdapter.ProdutosViewHolder(recycler.getChildAt(i)); **//Line 93**
if (holder.checkBox.isChecked()) {
holder.checkBox.setChecked(false);
}
}
use this one:
for (Product product : produtos){
product.setChecked(false);
}
recycler.getAdapter().notifyDataSetChanged();
I supppose your class Project has such method.
In a RecyclerView the item views are recycled so you dont have as many itemviews as item in your List. Instead those itemviews are recycled and shows differents elements of your productos List.
Your problem is that you are in a for loop with the length of the List but inside you are using that index to access itemviews wich has not that much elements.
Instead, you should define a variable in Producto.class and update every time that check/uncheck the CheckBox of the item. And set this variable to false when you want to uncheck all and call
adapter.notifyDataSetChanged();
UPDATE:
ProdutoAdapter.java
Define a method to access list produtos and update onBindViewHolder like this:
if (produtoOnCheckListener != null) {
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
produtos.get(position).setCheckBoxState(b);
produtoOnCheckListener.onCheckProduto(view, position);
}
});
}
MainActivity.class Define a ProductoAdapter variable and access to list productos to update the boolean value of each producto
[...]
ProductoAdapter productoAdapter = new ProductoAdapter();
[...]
for (int i = 0; i < productoAdapter.getItemCount(); i++) {
productoAdapter.getListProductos().get(i).setCheckBoxState(false);
}
productoAdapter.notifyDataSetChanged();
I have a list of tasks in recyclerview. Each task item has a check box to show if the task is completed or pending.
Now I want to show two sections in my list. One for checked items and another for unchecked items.
I have gone through this library to add the sections.
https://github.com/afollestad/sectioned-recyclerview
But how can I divide the items in list on the basis of they are checked or not?
Also I want to add the task into another section if checked or unchecked , i.e onClick.
If task is unchecked, and if I check it, it should get added to the completed section and vise versa.
I have a recyclerview now with swipe layout. Following is the adapter.
adapetr:
public class IAdapter extends RecyclerSwipeAdapter<IAdapter.ItemViewHolder> , SectionedRecyclerViewAdapter<IAdapter.ItemViewHolder> {
public ArrayList<Task> items;
Context conext;
public int _mId;
List<Task> itemsPendingRemoval = new ArrayList<>();
public IAdapter(Context context, ArrayList<Task> item) {
this.conext=context;
this.items=item;
}
#Override
public int getSectionCount() {
return 2;
}
#Override
public int getItemCount(int section) {
return items.size();
}
public static class ItemViewHolder extends RecyclerView.ViewHolder {
Task task;
CheckBox cb;
SwipeLayout swipeLayout;
TaskTableHelper taskTableHelper;
ItemViewHolder(final View itemView) {
super(itemView);
taskTableHelper= new TaskTableHelper(itemView.getContext());
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
cb = (CheckBox) itemView.findViewById(R.id.checkbox);
}
}
#Override
public void onBindViewHolder(final ItemViewHolder itemViewHolder,final int i) {
itemViewHolder.cb.setText(items.get(i).getTitle());
itemViewHolder.task = items.get(i);
int taskId = itemViewHolder.task.getId();
itemViewHolder.task = itemViewHolder.taskTableHelper.getTask(taskId);
int status = itemViewHolder.task.getStatus();
if(status == 0)
{
itemViewHolder.cb.setTextColor(Color.WHITE);
}
else {
itemViewHolder.cb.setChecked(true);
itemViewHolder.cb.setTextColor(Color.parseColor("#B0BEC5"));
}
itemViewHolder.cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
itemViewHolder.cb.setTextColor(Color.parseColor("#B0BEC5"));
itemViewHolder.task.setStatus(1);
itemViewHolder.taskTableHelper.updateStatus(itemViewHolder.task);
}
else
{
itemViewHolder.cb.setTextColor(Color.WHITE);
itemViewHolder.task.setStatus(0);
itemViewHolder.taskTableHelper.updateStatus(itemViewHolder.task);
}
}
});
final Task item = items.get(i);
itemViewHolder.swipeLayout.addDrag(SwipeLayout.DragEdge.Right,itemViewHolder.swipeLayout.findViewById(R.id.bottom_wrapper_2));
itemViewHolder.swipeLayout.setShowMode(SwipeLayout.ShowMode.LayDown);
itemViewHolder.swipeLayout.setOnDoubleClickListener(new SwipeLayout.DoubleClickListener() {
#Override
public void onDoubleClick(SwipeLayout layout, boolean surface) {
Toast.makeText(conext, "DoubleClick", Toast.LENGTH_SHORT).show();
}
});
itemViewHolder.swipeLayout.findViewById(R.id.trash2).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mItemManger.removeShownLayouts(itemViewHolder.swipeLayout);
items.remove(i);
notifyItemRemoved(i);
notifyItemRangeChanged(i, items.size());
mItemManger.closeAllItems();
itemViewHolder.taskTableHelper.deleteTask(item);
_mId = item.getAlertId();
cancelNotification();
Toast.makeText(view.getContext(), "Deleted " + itemViewHolder.cb.getText().toString() + "!", Toast.LENGTH_SHORT).show();
}
});
itemViewHolder.swipeLayout.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemViewHolder.task.setStatus(1);
itemViewHolder.taskTableHelper.updateStatus(itemViewHolder.task);
itemViewHolder.cb.setChecked(true);
Toast.makeText(conext, "Task Completed.", Toast.LENGTH_SHORT).show();
}
});
itemViewHolder.swipeLayout.getSurfaceView().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean mEditMode;
int id = item.getId();
int priority = item.getTaskPriority();
String title = item.getTitle();
String alertDate = item.getAlertDate();
String alertTime = item.getAlertTime();
String dueDate = item.getDueDate();
String dueTime = item.getDueTime();
_mId = item.getAlertId();
int listId = item.getList();
mEditMode = true;
Intent i = new Intent(conext, AddTaskActivity.class);
i.putExtra("taskId", id);
i.putExtra("taskTitle", title);
i.putExtra("taskPriority", priority);
i.putExtra("taskAlertTime", alertTime);
i.putExtra("taskAlertDate", alertDate);
i.putExtra("taskDueDate", dueDate);
i.putExtra("taskDueTime", dueTime);
i.putExtra("taskListId", listId);
i.putExtra("EditMode", mEditMode);
i.putExtra("AlertId",_mId);
conext.startActivity(i);
}
});
mItemManger.bindView(itemViewHolder.itemView, i);
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup,int position) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.card_layout, viewGroup, false);
return new ItemViewHolder(itemView);
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public void remove(int position) {
Task item = items.get(position);
if (itemsPendingRemoval.contains(item)) {
itemsPendingRemoval.remove(item);
}
if (items.contains(item)) {
items.remove(position);
notifyItemRemoved(position);
}
}
public void cancelNotification()
{
AlarmManager alarmManager = (AlarmManager)conext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(conext, NotificationReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(conext,_mId, intent, 0);
alarmManager.cancel(pendingIntent);
}
#Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
}
Can anyone help please?
Thank you..
You can add "sections" to your recyclerview with the library SectionedRecyclerViewAdapter.
First create a Section class to group your tasks:
class TaskSection extends StatelessSection {
String title;
List<Task> list;
public TaskSection(String title, List<Task> list) {
// call constructor with layout resources for this Section header, footer and items
super(R.layout.section_header, R.layout.section_item);
this.title = title;
this.list = list;
}
#Override
public int getContentItemsTotal() {
return list.size(); // number of items of this section
}
public int addTask(Task task) {
return list.add(task;
}
public int removeTask(Task task) {
return list.remove(task;
}
#Override
public RecyclerView.ViewHolder getItemViewHolder(View view) {
// return a custom instance of ViewHolder for the items of this section
return new MyItemViewHolder(view);
}
#Override
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
MyItemViewHolder itemHolder = (MyItemViewHolder) holder;
// bind your view here
itemHolder.tvItem.setText(list.get(position).getTitle());
}
#Override
public RecyclerView.ViewHolder getHeaderViewHolder(View view) {
return new SimpleHeaderViewHolder(view);
}
#Override
public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) {
MyHeaderViewHolder headerHolder = (MyHeaderViewHolder) holder;
// bind your header view here
headerHolder.tvItem.setText(title);
}
}
Then you set up the RecyclerView with your Sections:
// Create an instance of SectionedRecyclerViewAdapter
SectionedRecyclerViewAdapter sectionAdapter = new SectionedRecyclerViewAdapter();
// Create your sections with the list of data
TaskSection compSection = new TaskSection("Completed", compList);
TaskSection pendSection = new TaskSection("Pending", pendList);
// Add your Sections to the adapter
sectionAdapter.addSection(compSection);
sectionAdapter.addSection(pendSection);
// Set up your RecyclerView with the SectionedRecyclerViewAdapter
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(sectionAdapter);
Now if you want to send a task from "Pending" section to "Completed":
pendSection.removeTask(task);
compSection.addTask(task);
sectionAdapter.notifyDataSetChanged();
Regarding to the SwipeLayout, don't extend RecyclerSwipeAdapter, extend SectionedRecyclerViewAdapter and implement the SwipeLayout in ItemViewHolder / onBindItemViewHolder as you have done.