简体   繁体   中英

Card views inside a recycler view mess up after scrolling

I'm building an Android quiz app. Questions are saved in an SQLite database and are randomly picked out.

For each question answered, I store that answer in an ArrayList of Strings. At the end, I have a RecyclerView that shows card views containing a question and answers. I pass two lists to the constructor - the first one contains the questions (with answers) and the second one contains selected answers.

If the user's answer is correct, that answer is colored green. If it's incorrect, that answer is colored red and the correct answer is colored green.

When the result are shown, everything is correct. But after scrolling down so that the card can no longer be seen and then scrolling back up, the colors are no longer correct.

Screenshots: "Pravilen" means correct and "Napačen" means incorrect/wrong. In all 4 cases I picked the bottom answer (even if it was incorrect).

Before scrolling

After scrolling

Does anyone know why this happens? I've been trying to fix this for the past 2 days but I just don't see where it's going wrong. Thanks in advance.

Recycler view adapter code (sorry, the formatting may not be right):

public class RVAdapter extends RecyclerView.Adapter<RVAdapter.QuestionViewHolder> {

List<Question> questionList;
ArrayList<String> selectedAnswers;

public static class QuestionViewHolder extends RecyclerView.ViewHolder {
    CardView cardView;
    TextView question;
    TextView answer1;
    TextView answer2;
    TextView answer3;
    TextView answer4;

    QuestionViewHolder(View itemView) {
        super(itemView);
        cardView = (CardView)itemView.findViewById(R.id.cardView);
        question = (TextView)itemView.findViewById(R.id.resultQuestion);
        answer1 = (TextView)itemView.findViewById(R.id.resultAnswer1);
        answer2 = (TextView)itemView.findViewById(R.id.resultAnswer2);
        answer3 = (TextView)itemView.findViewById(R.id.resultAnswer3);
        answer4 = (TextView)itemView.findViewById(R.id.resultAnswer4);
    }
}


public RVAdapter(List<Question> questionList, ArrayList<String> selectedAnswers) {
    this.questionList = questionList;
    this.selectedAnswers = selectedAnswers;
}


@Override
public QuestionViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_view, viewGroup, false);
    return new QuestionViewHolder(view);
}


@Override
public void onBindViewHolder(QuestionViewHolder holder, int position) {
    holder.question.setText(questionList.get(position).getQuestion());

    String answer1 = questionList.get(position).getAnswer1();
    String answer2 = questionList.get(position).getAnswer2();
    String answer3 = questionList.get(position).getAnswer3();
    String answer4 = questionList.get(position).getAnswer4();
    String correctAnswer = questionList.get(position).getCorrectAnswer();
    String selectedAnswer = selectedAnswers.get(position);

    if (answer1 == null) {
        holder.answer1.setVisibility(View.GONE);
    } else {
        holder.answer1.setVisibility(View.VISIBLE);
        holder.answer1.setText(answer1);
        if (answer1.equals(correctAnswer)) {
            holder.answer1.setTextColor(Color.GREEN);
        } else if (answer1.equals(selectedAnswer)) {
            holder.answer1.setTextColor(Color.RED);
        }
    }
    if (answer2 == null) {
        holder.answer2.setVisibility(View.GONE);
    } else {
        holder.answer2.setVisibility(View.VISIBLE);
        holder.answer2.setText(answer2);
        if (answer2.equals(correctAnswer)) {
            holder.answer2.setTextColor(Color.GREEN);
        } else if (answer2.equals(selectedAnswer)) {
            holder.answer2.setTextColor(Color.RED);
        }
    }
    if (answer3 == null) {
        holder.answer3.setVisibility(View.GONE);
    } else {
        holder.answer3.setVisibility(View.VISIBLE);
        holder.answer3.setText(answer3);
        if (answer3.equals(correctAnswer)) {
            holder.answer3.setTextColor(Color.GREEN);
        } else if (answer3.equals(selectedAnswer)) {
            holder.answer3.setTextColor(Color.RED);
        }
    }
    if (answer4 == null) {
        holder.answer4.setVisibility(View.GONE);
    } else {
        holder.answer4.setVisibility(View.VISIBLE);
        holder.answer4.setText(answer4);
        if (answer4.equals(correctAnswer)) {
            holder.answer4.setTextColor(Color.GREEN);
        } else if (answer4.equals(selectedAnswer)) {
            holder.answer4.setTextColor(Color.RED);
        }
    }
}

At first I tried using a ListView but it wasn't that great. Then I googled around some more but still found nothing.

To fix my problem I reset the text to null and the color to black before setting my text and colors in my onBindViewHolder. This is the code:

@Override
public void onBindViewHolder(QuestionViewHolder holder, int position) {

    String question = questionList.get(position).getQuestion();
    String answer1 = questionList.get(position).getAnswer1();
    String answer2 = questionList.get(position).getAnswer2();
    String answer3 = questionList.get(position).getAnswer3();
    String answer4 = questionList.get(position).getAnswer4();
    String correctAnswer = questionList.get(position).getCorrectAnswer();
    String selectedAnswer = selectedAnswers.get(position);

    // Clear any previous attributes.
    holder.question.setText(null);
    holder.answer1.setText(null);
    holder.answer2.setText(null);
    holder.answer3.setText(null);
    holder.answer4.setText(null);
    holder.answer1.setTextColor(Color.BLACK);
    holder.answer2.setTextColor(Color.BLACK);
    holder.answer3.setTextColor(Color.BLACK);
    holder.answer4.setTextColor(Color.BLACK);

    holder.question.setText(question);
    // ... if statements follow below ...

you can set a tag in onBindViewHolder :

@Override
public void onBindViewHolder(QuestionViewHolder holder, int position) {
    holder.question.setText(questionList.get(position).getQuestion());
//add tags for all ViewHolder items
    holder.question.setTag(questionList.get(position));
    String answer1 = questionList.get(position).getAnswer1();
    String answer2 = questionList.get(position).getAnswer2();
    String answer3 = questionList.get(position).getAnswer3();
    String answer4 = questionList.get(position).getAnswer4();
    String correctAnswer = questionList.get(position).getCorrectAnswer();
    String selectedAnswer = selectedAnswers.get(position);

    if (answer1 == null) {
        holder.answer1.setVisibility(View.GONE);
    } else {
        holder.answer1.setVisibility(View.VISIBLE);
        holder.answer1.setText(answer1);
        if (answer1.equals(correctAnswer)) {
            holder.answer1.setTextColor(Color.GREEN);
        } else if (answer1.equals(selectedAnswer)) {
            holder.answer1.setTextColor(Color.RED);
        }
    }
    if (answer2 == null) {
        holder.answer2.setVisibility(View.GONE);
    } else {
        holder.answer2.setVisibility(View.VISIBLE);
        holder.answer2.setText(answer2);
        if (answer2.equals(correctAnswer)) {
            holder.answer2.setTextColor(Color.GREEN);
        } else if (answer2.equals(selectedAnswer)) {
            holder.answer2.setTextColor(Color.RED);
        }
    }
    if (answer3 == null) {
        holder.answer3.setVisibility(View.GONE);
    } else {
        holder.answer3.setVisibility(View.VISIBLE);
        holder.answer3.setText(answer3);
        if (answer3.equals(correctAnswer)) {
            holder.answer3.setTextColor(Color.GREEN);
        } else if (answer3.equals(selectedAnswer)) {
            holder.answer3.setTextColor(Color.RED);
        }
    }
    if (answer4 == null) {
        holder.answer4.setVisibility(View.GONE);
    } else {
        holder.answer4.setVisibility(View.VISIBLE);
        holder.answer4.setText(answer4);
        if (answer4.equals(correctAnswer)) {
            holder.answer4.setTextColor(Color.GREEN);
        } else if (answer4.equals(selectedAnswer)) {
            holder.answer4.setTextColor(Color.RED);
        }
    }

I have implemented your problem in a little different way, hope it helps.

public class Question {
List<String> options = new ArrayList<String>();
String correctAnswer;
String question;

public List<String> getOptions() {
    return options;
}

public String getCorrectAnswer() {
    return correctAnswer;
}

public String getQuestion() {
    return question;
}

public void setOptions(List<String> options) {
    this.options = options;
}

public void setCorrectAnswer(String correctAnswer) {
    this.correctAnswer = correctAnswer;
}

public void setQuestion(String question) {
    this.question = question;
  }
}


public class selectedAnswer {
String selectedAnswer;

public String getSelectedAnswer() {
    return selectedAnswer;
}

public void setSelectedAnswer(String selectedAnswer) {
    this.selectedAnswer = selectedAnswer;
 }
}

public class RVAdapter extends RecyclerView.Adapter<RVAdapter.QuestionViewHolder> {

List<Question> questionList = new ArrayList<>();
List<selectedAnswer> selectedAnswers = new ArrayList<>();

public static class QuestionViewHolder extends RecyclerView.ViewHolder {
    CardView cardView;
    TextView question;
    TextView answer1;
    TextView answer2;
    TextView answer3;
    TextView answer4;

    QuestionViewHolder(View itemView) {
        super(itemView);
        cardView = (CardView) itemView.findViewById(R.id.cardView);
        question = (TextView) itemView.findViewById(R.id.resultQuestion);
        answer1 = (TextView) itemView.findViewById(R.id.resultAnswer1);
        answer2 = (TextView) itemView.findViewById(R.id.resultAnswer2);
        answer3 = (TextView) itemView.findViewById(R.id.resultAnswer3);
        answer4 = (TextView) itemView.findViewById(R.id.resultAnswer4);
    }
}


public RVAdapter(List<Question> questionList, List<selectedAnswer> selectedAnswers) {
    this.questionList = questionList;
    this.selectedAnswers = selectedAnswers;
}


@Override
public QuestionViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_view, viewGroup, false);
    return new QuestionViewHolder(view);
}


@Override
public void onBindViewHolder(QuestionViewHolder holder, int position) {
    holder.answer1.setVisibility(View.GONE);
    holder.answer2.setVisibility(View.GONE);
    holder.answer3.setVisibility(View.GONE);
    holder.answer4.setVisibility(View.GONE);
    holder.question.setText(questionList.get(position).getQuestion());
    if(questionList.get(position).getCorrectAnswer() == selectedAnswers.get(position).getSelectedAnswer())
    {
        holder.answer1.setText(selectedAnswers.get(position).getSelectedAnswer());
        holder.answer1.setVisibility(View.VISIBLE);
        holder.answer1.setTextColor(Color.GREEN);
        questionList.get(position).getOptions().remove(position);
    }

    else
    {
        for(int i=0;i<questionList.get(position).getOptions().size();i++) {
            if(selectedAnswers.get(position).getSelectedAnswer() == questionList.get(position).getOptions().get(i))
            {
                holder.answer2.setText(selectedAnswers.get(position).getSelectedAnswer());
                holder.answer2.setVisibility(View.VISIBLE);
                holder.answer2.setTextColor(Color.RED);
                questionList.get(position).getOptions().remove(position);
            }
        }
    }
    if(questionList.get(position).getOptions().size() != 0)
    {
        holder.answer3.setText(questionList.get(position).getOptions().get(2));
        holder.answer3.setVisibility(View.VISIBLE);
        holder.answer4.setText(questionList.get(position).getOptions().get(3));
        holder.answer4.setVisibility(View.VISIBLE);
    }

  }
}

I had the same problem and the only solution I found for this is:

holder.setIsRecyclable(false);

I have faced this issue and realised that in my case I was toggling view visibility inside public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}

So what was happening is due to bad code on my part sometimes some of the viewholders were getting completely hidden and hence were not getting removed or recylcled. This caused the randomness in the recylerview. So if you have some code that changes the view visibility then remove that and test if the issue is still there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM