简体   繁体   English

滚动后,回收站视图中的卡片视图混乱

[英]Card views inside a recycler view mess up after scrolling

I'm building an Android quiz app. 我正在构建一个Android测验应用程序。 Questions are saved in an SQLite database and are randomly picked out. 问题被保存在SQLite数据库中并被随机挑选出来。

For each question answered, I store that answer in an ArrayList of Strings. 对于每个回答的问题,我都将该回答存储在字符串的ArrayList中。 At the end, I have a RecyclerView that shows card views containing a question and answers. 最后,我有一个RecyclerView,它显示包含问题和答案的卡片视图。 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. 屏幕截图: “ Pravilen”表示正确,“Napačen”表示错误/错误。 In all 4 cases I picked the bottom answer (even if it was incorrect). 在所有4种情况下,我都选择了最底层的答案(即使答案不正确)。

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. 最初,我尝试使用ListView,但是效果不是很好。 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. 为了解决我的问题, 将我的文本和颜色设置在onBindViewHolder中之前,我将文本重置为null并将颜色重置为黑色。 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 : 您可以在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); owner.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) {} 我已经遇到了这个问题,并意识到在我的情况下,我是在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. 这导致了recylerview中的随机性。 So if you have some code that changes the view visibility then remove that and test if the issue is still there. 因此,如果您有一些更改视图可见性的代码,请删除该可见性并测试问题是否仍然存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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