I am working on app that using RecyclerView. I have a Button in each card that when clicked, will count the number of clicks and display it in a TextView in that particular card. The app crashes (Logic Error ) when I run it. What am I doing wrong ?
( I want to setcheck the check box true when counter = counter in Model )
public class MorAdapter extends RecyclerView.Adapter<MorAdapter.HViewholder> {
private ArrayList<ZekeritemModel> model=new ArrayList<>();
public MorAdapter(ArrayList<ZekeritemModel> models,Context context) {
this.model = models;
}
#Override
public HViewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View v = layoutInflater.inflate(R.layout.mor_items, parent, false);
return new HViewholder(v);
}
#Override
public void onBindViewHolder(#NonNull MorAdapter.HViewholder holder, int position) {
holder.plusbtn.setOnClickListener(new View.OnClickListener() {
int count =0;
#Override
public void onClick(View v) {
count++;
holder.plustext.setText(Integer.toString(count));
if (count==model.get(position).getCounter()){
holder.checkBox.setChecked(true);}
}
});
}
#Override
public int getItemCount() {
return model.size();
}
class HViewholder extends RecyclerView.ViewHolder {
TextView plustext;
CircleButton plusbtn;
CheckBox checkBox;
HViewholder(View itemView) {
super(itemView);
plusbtn=itemView.findViewById(R.id.pluss);
plustext=itemView.findViewById(R.id.plustext);
checkBox=itemView.findViewById(R.id.checkk);
}
}
}
add currentCount property to your model ZekeritemModel
so your model became
public class ZekeritemModel {
.... your code
....
int currentCount = 0;
// add your getter and setter ..
}
change your onBind to
#Override
public void onBindViewHolder(#NonNull MorAdapter.HViewholder holder, int position) {
// get current item
final ZekeritemModel item = model.get(position);
int count = item.getCurrentCount();
// set value of counter inside textview
holder.plustext.setText(Integer.toString(count));
holder.plusbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count++;
item.setCurrentCount(count);
holder.plustext.setText(Integer.toString(count));
if (count==model.get(position).getCounter()){
holder.checkBox.setChecked(true);}
}
});
}
NOTE may code some typo or miss some taps, spaces, parenthesis (as i Have no IDE now).
Because you declared "counter" as global , you must to add counter to your model
Related
I try to update the list item weight code work fine
#NonNull
#Override
public viewlistx onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View xd = getLayoutInflater().inflate(R.layout.lay_yesno_list,parent,false);
return new viewlistx(xd);
}
#Override
public void onBindViewHolder(#NonNull viewlistx holder, final int position) {
btyesi = holder.btyes;
holder.btyes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.w("click","pos: " + position);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) btyesi.getLayoutParams();
params.weight = 2.0f;
btyesi.setLayoutParams(params);
}
});
}
#Override
public int getItemCount() {
return 4;
}
public class viewlistx extends RecyclerView.ViewHolder{
private final TextView btyes;
public viewlistx(#NonNull View itemView) {
super(itemView);
btyes = itemView.findViewById(R.id.yesbtx);
}
}
}
but the problem is when I click an item it changes the next item weight
for example pos, 0 click pos 1 item value change or pos 1 clicked pos 2 item value change
What's I'm doing wrong?
found way to fix that for use value animation on list must change
holder
to
final holder
and its work fine
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.
I have the following AssessmentAdapter class. In the constructor of my ViewHolder class, I findViewById() to get the ImageView with the delete icon, and assign the click event to it.
I am trying to find the position of my ViewHolder, and send this to the parameterized constructor of my OnDeleteIconClicked class, but the position is always -1. Why?
Here is my code:
public class AssessmentAdapter extends RecyclerView.Adapter<AssessmentAdapter.AssessmentViewHolder> {
private List<Assessment> assessmentList;
private IAssessmentsList context;
public AssessmentAdapter(List<Assessment> assessmentList, IAssessmentsList context){
this.assessmentList = assessmentList;
this.context = context;
}
#Override
public AssessmentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View rowView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.assessment_list_row, parent, false);
rowView.setOnClickListener(new OnAdapterItemClicked());
return new AssessmentViewHolder(rowView);
}
#Override
public void onBindViewHolder(AssessmentViewHolder holder, int position) {
Assessment assessment = assessmentList.get(position);
holder.txtClientName.setText(assessment.getClient());
holder.txtAssessmentDate.setText(assessment.getInspectedDate());
holder.imageView.setTag(assessment.getId());
}
#Override
public int getItemCount() {
return assessmentList.size();
}
public class AssessmentViewHolder extends RecyclerView.ViewHolder{
public TextView txtClientName, txtAssessmentDate;
public ImageView imageView;
public AssessmentViewHolder(View view){
super(view);
txtClientName = view.findViewById(R.id.txtClientName);
txtAssessmentDate = view.findViewById(R.id.txtAssessmentDate);
imageView= view.findViewById(R.id.deleteAssessment);
int layoutPosition = getLayoutPosition(); //always -1
int adapterPosition = getAdapterPosition(); //always -1
imageView.setOnClickListener(new OnDeleteIconClicked(getAdapterPosition()));
}
}
public class OnAdapterItemClicked implements View.OnClickListener{
#Override
public void onClick(View v) {
context.OnAdapterItemClicked(v);
}
}
public class OnDeleteIconClicked implements View.OnClickListener {
private int position;
public OnDeleteIconClicked(int position){
this.position = position;
}
#Override
public void onClick(View v) {
context.OnDeleteItemClicked(Integer.parseInt(v.getTag().toString()), position);
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
}
}
imageView.setOnClickListener(new OnDeleteIconClicked(getAdapterPosition()));
Take the line above and place it inside onBindViewHolder like so:
#Override
public void onBindViewHolder(AssessmentViewHolder holder, int position) {
Assessment assessment = assessmentList.get(position);
holder.txtClientName.setText(assessment.getClient());
holder.txtAssessmentDate.setText(assessment.getInspectedDate());
holder.imageView.setTag(assessment.getId());
holder.imageView.setOnClickListener(new OnDeleteIconClicked(position));
}
but the position is always -1. Why?
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view,
inside ViewHolder { ....
...
view.setOnClickListener(new View.OnClickListener) {
#Override
public void onClick(View v) {
int position = getAdapterPosition(); // This does not return -1, because calculation is done and views have been inflated.
}
}
);
....
}
Put your click event inside onBindViewHolder
holder.imageView.setOnClickListener(new OnDeleteIconClicked(position));
public class AssessmentViewHolder extends RecyclerView.ViewHolder {
public TextView txtClientName, txtAssessmentDate;
public ImageView imageView;
public AssessmentViewHolder(View view) {
super(view);
txtClientName = view.findViewById(R.id.txtClientName);
txtAssessmentDate = view.findViewById(R.id.txtAssessmentDate);
imageView = view.findViewById(R.id.deleteAssessment);
int layoutPosition = getLayoutPosition(); //always -1
int adapterPosition = getAdapterPosition(); //always -1
// When intialise viewholder value of getAdapterPosition will be always -1
// instead of passing value from constructor, get when onClick event occure
imageView.setOnClickListener(new OnDeleteIconClicked());
} }
Change in OnDeleteIconClicked
public class OnDeleteIconClicked implements View.OnClickListener {
private int position;
#Override
public void onClick(View v) {
this.position = getAdapterPosition();
context.OnDeleteItemClicked(Integer.parseInt(v.getTag().toString()), position);
}
public int getPosition() {
return position;
}
}
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view, call it in the public void onClick(final View v) method for example:
"#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final Students user = mUsers.get(position);
holder.Name.setText(user.getFullname());
holder.Index.setText(user.getIndex_number());
if (user.getThumbnail().equals("default")) {
holder.profile_image.setImageResource(R.drawable.profile_pic);
} else {
Picasso.get().load(user.getThumbnail())
.placeholder(R.drawable.profile_pic)
.into(holder.profile_image);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
**list_user_id = mUsers.get(position).getId();**
Intent Sub = new Intent(mContext, UserProfileActivity.class);
Sub.putExtra("user_id1", list_user_id);
mContext.startActivity(Sub);
BUT NOT
getAdapterPosition(); It will always return -1 when recyclerview makes layout calculations. You are calling this methods inside ViewHolder.. It means RecyclerView is doing calculations.
If you need position inside click actions of view, call it in the public void onClick(final View v) method for example:
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final Students user = mUsers.get(position);
holder.Name.setText(user.getFullname());
holder.Index.setText(user.getIndex_number());
**list_user_id = mUsers.get(position).getId();**
if (user.getThumbnail().equals("default")) {
holder.profile_image.setImageResource(R.drawable.profile_pic);
} else {
Picasso.get().load(user.getThumbnail())
.placeholder(R.drawable.profile_pic)
.into(holder.profile_image);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
Intent Sub = new Intent(mContext, UserProfileActivity.class);
Sub.putExtra("user_id1", list_user_id);
mContext.startActivity(Sub);
In my application i have horizontal list view. On Item select I want to change that selected Item background color and it's text view color. i have figured out that part. But how to reset background color and text view color of previously selected item. here's my adapter class.
public class DateRangeListViewAdapter extends RecyclerView.Adapter<DateRangeListViewAdapter.ContentViewHolder> {
private ItemClickListener itemClickListener;
private LayoutInflater inflater;
private ArrayList<String> data;
private Context context;
private int dataType;
private int previousSelectedPosition;
private static final int DATE_TYPE = 1;
private static final int STATUS_TYPE = 2;
public DateRangeListViewAdapter(ArrayList<String> data, Context context,int dataType) {
this.data = data;
this.context = context;
this.dataType = dataType;
inflater = LayoutInflater.from(context);
previousSelectedPosition = -1;
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_date_range_list_item,parent,false);
return new ContentViewHolder(view);
}
#Override
public void onBindViewHolder(ContentViewHolder holder, int position) {
String name = data.get(position);
holder.dateText.setText(name);
}
#Override
public int getItemCount() {
return data.size();
}
public class ContentViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private FrameLayout main;
private TextView dateText;
public ContentViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
main = (FrameLayout) itemView.findViewById(R.id.main_layout);
dateText = (TextView) itemView.findViewById(R.id.date_name);
}
#Override
public void onClick(View v) {
//Selected item color change
main.setBackground(ContextCompat.getDrawable(context,R.drawable.date_range_selected_item_background));
dateText.setTextColor(ContextCompat.getColor(context,R.color.colorPrimary));
if(itemClickListener!=null){
itemClickListener.onItemClick(v,this.getLayoutPosition(),dataType,getOldPosition());
}
}
}
public interface ItemClickListener{
public void onItemClick(View v, int position,int dataType,int oldPosition);
}
}
You basically want to make good use of your int flag, previousSelectedPosition, to keep track of the list item's position that was clicked, invoke notifyDataSetChanged(), and then set the flag as part of a conditional statement within onBindViewHolder() to update ViewHolder's views accordingly as they continuously get binded. Try the following changes:
ViewHolder's onClick():
#Override
public void onClick(View v) {
if (itemClickListener!=null) {
previousSelectedPosition = getAdapterPosition();
notifyDataSetChanged();
itemClickListener.onItemClick(v,this.getLayoutPosition(),dataType,getOldPosition());
}
}
RecyclerView.Adapter's onBindViewHolder():
#Override
public void onBindViewHolder(ContentViewHolder holder, int position) {
String name = data.get(position);
holder.dateText.setText(name);
if (previousSelectedPosition == position) {
main.setBackground(ContextCompat.getDrawable(context,R.drawable.date_range_selected_item_background));
dateText.setTextColor(ContextCompat.getColor(context,R.color.colorPrimary));
} else {
// TODO: Configure the FrameLayout and TextView here for initial runtime as well as back to default
}
}
... and yes, make sure to keep previousSelectedPosition initialized as -1 for the initial runtime just so the condition in onBindViewHolder() wouldn't matter until the flag updates (after a list item is clicked, that is).
Your OnClickListener does not work perfectly. You just need to implements your ViewHolder from you "ItemClickListener" interface. And add this line in onCreateViewHolder :
View view = inflater.inflate(R.layout.custom_date_range_list_item,parent,false);
ContentViewHolder cVh = ContentViewHolder(view);view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cVh.onItemClick(v,this.getLayoutPosition(),cVh .dataType,cVh .getOldPosition());
}
});return cVh
I'm setting a RecyclerView behaving like a list, I want a button in the bottom of the list that when clicked adds more views, I'm thinking the easier way to do it is to make the position 0 as the first one in the bottom, and increasing the position to the top, so I can add views when the the view in position 0 is clicked.
If there is a better aproach for this problem do share.
Here is my adapter:
public class AddEventsAdapter extends RecyclerView.Adapter<AddEventsAdapter.ViewHolder> {
public List<String> items = new ArrayList<>();
public void addItem(String name) {
notifyItemInserted(items.size() - 1);
items.add(name);
}
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, items.size());
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.add_event_item, parent, false);
return new ViewHolder(view);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setData(position);
holder.eventName.setText(i + "");
if(position == 0)
{
holder.theLayout.setBackgroundColor(Color.parseColor("#7F9099"));
holder.eventName.setText("Add");
}
}
static int i;
class ViewHolder extends RecyclerView.ViewHolder{
public TextView eventName;
public RelativeLayout theLayout;
public ViewHolder(final View itemView) {
super(itemView);
eventName = (TextView)itemView.findViewById(R.id.eventName);
theLayout = (RelativeLayout)itemView.findViewById(R.id.backgroundevent);
theLayout.setId(++i);
}
public void setData(final int position) {
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (position == items.size() - 1) {
addItem("");
} else {
removeItem(position);
}
}
});
}
}
}
You may notice some errors in that, I've been over it for the last 10 hours and I'm having a logic breakdown
It's solved by addind this line to the LayoutManager .setReverseLayout(true);
you can add a footer view at the end of the list and inside that you can add your button. This is the link to create a footer in recycler view https://github.com/u3breeze/android-RecyclerView-WithHeaderAndFooter. You can add the views in the normal way