Reputation: 113
I am building an app where publishers upload questions to database. Publishers can add as many questions they want, so i used a recycler view to handle that. When publisher clicks the button to add question a new layout is inflated as specified in my recyclerview adapter. TopicQuestionsAdapter is the name of my recycler view adapter
...
RecyclerView addTopicOfTheDayWhereDynamicLayoutsWillBeAdded;
TopicQuestionsAdapter topicQuestionsAdapter;
ArrayList<TopicQuestions> topicQuestionsList;
addTopicOfTheDayWhereDynamicLayoutsWillBeAdded.setHasFixedSize(true);
addTopicOfTheDayWhereDynamicLayoutsWillBeAdded.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
topicQuestionsList = new ArrayList<>();
...
addTopicOfTheDayAddQuiz.setOnClickListener(v29 -> {
...
// dynamically add questions layout on subsequent clicks
// here with an x button in each layout to remove the
// entire question layout
topicQuestionsList.add(new TopicQuestions());
topicQuestionsAdapter = new TopicQuestionsAdapter("Adapter", getContext(), topicQuestionsList);
addTopicOfTheDayWhereDynamicLayoutsWillBeAdded.setAdapter(topicQuestionsAdapter);
topicQuestionsAdapter.notifyItemInserted(topicQuestionsList.size());
}
});
Now the recycler view layout consists of four FABs to add the different types of questions and options, one textview and one image button to remove the whole view
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopicQuestionsViewHolder {
//R.layout.add_question_layout is the layout
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.add_question_layout, parent, false)
return TopicQuestionsViewHolder(itemView)
}
/*this is where my problem is i observed that whenever i
add a new question, the layouts i had already added to previous
views get cleared. Recycler view destroys states*/
override fun onBindViewHolder(holder: TopicQuestionsViewHolder, position: Int) {
// the textview to show this question number
holder.questionNumber.text = "${position + 1}."
// the image button to remove the whole view
holder.removeQuestion.setOnClickListener {
topicQuestions.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, topicQuestions.size)
}
holder.addField.setOnClickListener {
// need to fix this
when (holder.theFields.visibility == View.GONE) {
true -> {
holder.theFields.visibility = View.VISIBLE
holder.addField.setImageResource(R.drawable.close)
Log.wtf(TAG, "true")
}
false -> {
holder.theFields.visibility = View.GONE
holder.addField.setImageResource(R.drawable.add)
Log.wtf(TAG, "false")
}
}
}
// this button would add a question field to this view
holder.addQuestionField.setOnClickListener {
val lParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
lParams.topMargin = 16
val view = LayoutInflater.from(ctx).inflate(R.layout.add_question_field_to_question_layout, null)
view.layoutParams = lParams
holder.toAddViews.addView(view)
}
// this button would add an image question field to this view
holder.addImageQuestionField.setOnClickListener {
Log.wtf(TAG, "image question will be added here")
}
// this button would add toggle option to this view
holder.addToggleOption.setOnClickListener {
Log.wtf(TAG, "toggle option will be added here")
}
// this button would add check box option to this view
holder.addCheckBoxOption.setOnClickListener {
Log.wtf(TAG, "check box option will be added here")
}
}
as i had hinted earlier in my code whenever i click on the addTopicOfTheDayAddQuiz button which is supposed to add another view below the already exiting one(s) all child views inside the already existing views are cleared. Please what is a better approach to fix this issue?
Upvotes: 1
Views: 103
Reputation: 13019
Your Adapter is doing a lot of work in onBindViewHolder()
: setting up lots of click listeners which in turn toggle the UI so the users can enter their question details without being bothered by UI elements they don't need.
BUT you do not seem to keep track anywhere of the selections the users made for each question. AND each time the user adds a new question, you throw away the existing Adapter:
topicQuestionsAdapter = new TopicQuestionsAdapter("Adapter", getContext(), topicQuestionsList); addTopicOfTheDayWhereDynamicLayoutsWillBeAdded.setAdapter(topicQuestionsAdapter);
Since you did not share enough code for me to debug your app and test my solution, I'll just sketch some ideas:
Instead of using a new Adapter each time a new question is created, just add the question to the list and then call (please note: topicQuestionsList.size() - 1)
topicQuestionsAdapter.notifyItemInserted(topicQuestionsList.size() - 1);
One other thing you need to do is keep track of the states of each list item (which Button
s etc. are visible, what is the content of EditText
s if there are any...). If the list gets longer and the users need to scroll, onBindViewHolder()
will be called repeatedly even if you keep working with the same Adapter.
So you need a class - let's call it ListEntry
- with fields to reflect the possible states of a list item. And inside the Adapter, you can keep a List<ListEntry>
with one ListEntry
for each item of your data list. Each time some Button
becomes visible, you update the corresponding ListEntry
. In onBindViewHolder()
you evaluate the ListEntry
for the given position and set the attributes of the child View
s of holder.itemView
accordingly.
Upvotes: 2