I am using this tutorial to build an itemTouchListener for my RecyclerView. The recyclerview is filled with more items than the screen fits (more than 10), so recycling gets into action. The itemtouchHelper handles both up-down and left-right movement. After 2 days of struggle (had setStableIds to true which caused flickering of the viewholder views when the were moved up-down), I finally got a better behaviour. My code of the crucial features:
@Override
public int getItemCount() {
return questionlist.size();
}
@Override
public void onViewMoved(int oldPosition, int newPosition) {
targetqueobj = questionlist.get(oldPosition);
this.fromPosition = oldPosition;
this.toPosition = newPosition;
questionlist.remove(targetqueobj);
questionlist.add(newPosition, targetqueobj);
// targetqueobj.setinturn(toPosition+1);
}
@Override
public void onViewSwiped(final RecyclerView.ViewHolder thisviewholder,final int position, int direction) {
targetqueobj = questionlist.get(position);
if (direction == ItemTouchHelper.LEFT){
// saveqset();
Intent intent = new Intent(context, QuestionEditActivity.class);
intent.putExtra("com.logictop.mqapp.QuestionObjParcelable",targetqueobj);
context.startActivity(intent);
}
if (direction == ItemTouchHelper.RIGHT) {
// DIALOG
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.remove_question);
builder.setNegativeButton(R.string.No, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
// thisviewholder.itemView.setAlpha(1);
notifyDataSetChanged();
}
});
builder.setPositiveButton(R.string.Yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
questionlist.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount()-position);
}
});
Dialog dialog = builder.create();
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
}
if (direction == ItemTouchHelper.RIGHT) {
// DIALOG
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.remove_question);
builder.setNegativeButton(R.string.No, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
thisviewholder.itemView.setAlpha(1);
notifyDataSetChanged();
}
});
builder.setPositiveButton(R.string.Yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
questionlist.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount()-position);
}
});
Dialog dialog = builder.create();
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
}
The problem is this. Though the recyclerview runs smoothly with the items very nicely changing positions, when an item is swiped away, sometimes another item looks also removed when the recyclerview is scrolled down (so it seems that the other item that gets removed fills the same "screen" position in the recyclerview after it is scrolled). It doesn't happen every time and it mostly happens when a view in some specific positions are swiped away. That "gap" can be mended if I move a neighbor view up or down.
I have tried every solution I found in here (notifyDataChanged, notifyItemRangeChanged (with every parameter compination). But nothing could get me a stable behaviour. AFter a lot of stackoverflow searching I decided to follow the advice of holder.setIsRecyclable(false)
even though I didn't want to do that (as it eliminates the point of having a recyclerview after all). But in that case, other problems appear. You'll see below that when most of the views are swiped away, they lower ones won't leave the screen, even though they apparently have "left the adapter" (cannot swipe them away). And in the end, the last views stay stuck.
I have tested both ways on a completely new project with nothing external coming into the way. I have tried putting notifyDataChanged()
in an overriden function of clearView. Nothing seems to provide a rock solid stable recyclerview that won't get at some point a gap in itself.
The question now: is there a way to make a recyclerview with working recycling behave like it is supposed to behave or should I accept that situation? Thank you very much for your attention!
UPDATE 1----------------------------
As I was told there could be an issue with this thisviewholder.itemView.setAlpha(1);
I commented it out along with the corresponding overriden onChildDraw (the whole of it) that is used to fade the view out when it is swiped out. So now nothing gets invisible. Still the problem persists.
UPDATE 2---------------------------- I have enforced stableIds (had already done that once and it didn't work)
@Override
public long getItemId(int position){
return questionlist.get(position).getquestionid();
}
and the adapter contructor
public QSetEditAdapter(ArrayList<QuestionObj_prcl> questionlist, Context context) {
this.context = context;
this.questionlist = questionlist;
setHasStableIds(true);
}
Still the problem persists.
UPDATE 3---------------------------- I ended up using a different tutorial and now everything works as expected. Thanks a lot!
Change your adapter this way:
Set hasStableIds() to true.
Implement getItemId(int) and return unique ids for your items.