hey guys Im trying to use swipe inside onBindViewHolder because my items are from the database but I think it doesnt seem to work cuz my app is crashing. Im using this custom cursor adapter for my recyclerview https://gist.github.com/skyfishjy/443b7448f59be978bc59 here is my code.
#Override
public void onBindViewHolder(ItemViewHolder viewHolder, Cursor cursor) {
mItems = cursor;
final int id = cursor.getInt(cursor.getColumnIndex(MyDBHandler.COLUMN_ID));
final String title = cursor.getString(cursor.getColumnIndex(MyDBHandler.COLUMN_TITLE_REMINDER));
final String desc = cursor.getString(cursor.getColumnIndex(MyDBHandler.COLUMN_DESC_REMINDER));
final String date = cursor.getString(cursor.getColumnIndex(MyDBHandler.COLUMN_DATE_REMINDER));
viewHolder.title.setText(title);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, String.valueOf(id), Toast.LENGTH_SHORT).show();
}
});
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
int itemPosition = viewHolder.getAdapterPosition();
notifyItemRemoved(itemPosition);
dbHandler.deleteReminder(id);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(this.myRecyclerview);
}
Is there anyway I can do swiping to dismiss my items in recyclerview?
Remove the following chunk of code from onBindViewHolder and add in your activity or fragment from where you are initializing adapter.
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { // type cast your view holder
// CusrsorViewHolder cViewHolder = (CursorViewHolder)viewHolder;
int itemPosition = viewHolder.getAdapterPosition();
notifyItemRemoved(itemPosition);
dbHandler.deleteReminder(cViewHolder.id);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(this.myRecyclerview);
//put the above code before the following method in your activity or fragment
//this.RecylerView.setAdapter(adapter)
Set your id in onBindViewHolder
#Override
public void onBindViewHolder(ItemViewHolder viewHolder, Cursor cursor) {
mItems = cursor;
final int id = cursor.getInt(cursor.getColumnIndex(MyDBHandler.COLUMN_ID));
viewHolder.id = id;
}
thanks to #Waleed Sarwar for helping me solve it.
I was using https://gist.github.com/skyfishjy/443b7448f59be978bc59 for my recyclerviewcursoradapter.
MainActivity.java
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
RemindersAdapter.ItemViewHolder itemViewHolder = (RemindersAdapter.ItemViewHolder)viewHolder;
int itemPosition = itemViewHolder.getAdapterPosition();
adapter.notifyItemRemoved(itemPosition);
// get the id of an item via itemViewHolder.id
dbHandler.deleteReminder(itemViewHolder.id);
// update cursor upon deleting do avoid
// the card from coming back upon swipe
adapter.swapCursor(dbHandler.getAllReminders());
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(listReminder);
RemindersAdapter.java
#Override
public void onBindViewHolder(ItemViewHolder viewHolder, Cursor cursor) {
final int id = cursor.getInt(cursor.getColumnIndex(MyDBHandler.COLUMN_ID));
final String title = cursor.getString(cursor.getColumnIndex(MyDBHandler.COLUMN_TITLE_REMINDER));
final String desc = cursor.getString(cursor.getColumnIndex(MyDBHandler.COLUMN_DESC_REMINDER));
final String date = cursor.getString(cursor.getColumnIndex(MyDBHandler.COLUMN_DATE_REMINDER));
viewHolder.title.setText(title);
// pass id to viewholder to get in swipe
viewHolder.id = id;
}
public class ItemViewHolder extends RecyclerView.ViewHolder{
public int id;
TextView title;
public ItemViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.reminderTitle);
}
}
Im using adapter.swapCursor(dbHandler.getAllReminders()); from my adapter which was a method from abstract class CursorRecyclerViewAdapter that makes the cursor updated upon deleting because without it, the deleted item will be recreated by onBindViewHolder.
Use the below code to delete the item from the list. orderlist is the RecyclerView variable.
SwipeDismissRecyclerViewTouchListener touchListener =
new SwipeDismissRecyclerViewTouchListener(
orderlist,
new SwipeDismissRecyclerViewTouchListener.DismissCallbacks() {
#Override
public boolean canDismiss(int position) {
return true;
}
#Override
public void onDismiss(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
/*db.deleteOrderProduct(ordereditems.get(position).getOrder_pro_Code());
if(position>1){
listposition = position-1;
}*/
//ordereditems.remove(position);
//adapter.notifyItemRemoved(position);
//adapter.notifyDataSetChanged();
//displayOrderList();
DeleteOrderById(position);
}
adapter.notifyDataSetChanged();
}
});
orderlist.setOnTouchListener(touchListener);
Related
I have a basic RecyclerView list and added a ItemTouchHelper in order to drag and drop list items.
The problem I have with it is that it runs onMove on every single list item it passes and it's lagging the app real hard.
Is there a way to implement it so that onMove only runs when I release my hold on a RecyclerView list item?
Thanks.
MainActivity.java
public class pillar_sort extends AppCompatActivity {
private MyRecyclerViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Initialize layout
super.onCreate(savedInstanceState);
setContentView(R.layout.pillar_sort);
final SharedPreferences sharedPref = // Get SharedPreferences
final ArrayList<String> modules = // Import a list
final ArrayList<Boolean> visibility = // Import a list
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(this, modules, visibility, cardcolor, txtcolor);
recyclerView.setAdapter(adapter);
VerticalSpaceItemDecoration decor = new VerticalSpaceItemDecoration();
recyclerView.addItemDecoration(decor);
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP|ItemTouchHelper.DOWN, 0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder dragged, #NonNull RecyclerView.ViewHolder target) {
int position_dragged = dragged.getAdapterPosition();
int position_target = target.getAdapterPosition();
Collections.swap(modules,position_dragged,position_target);
adapter.notifyItemMoved(position_dragged,position_target);
adapter.notifyDataSetChanged();
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
});
helper.attachToRecyclerView(recyclerView);
}
MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
// Variables go here
MyRecyclerViewAdapter( /* a lot of data to pass onto the adapter */ ) {
// get data from MainActivity and put on variables
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
CardView card = view.findViewById(R.id.card);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position){
// Put data to TextViews and set card color
}
#Override
public int getItemCount() {
return modules.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
ImageButton image_visibility;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.rowText);
image_visibility = itemView.findViewById(R.id.imageButton);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
}
}
I'm trying to make recyclerView item change color on swipe so it's will be highlited because on swipe i open an AlertDialog so the person will recognize which one item he is changing.
But my main issue is that when i try to change the background color by using
viewHolder.itemView.setBackgroundColor(Color.parseColor("#cc0000"));
Nothing is heppening, here is my full code from the builder of recyclerView
public void buildTopRecyclerView(){
mRecyclerViewTOP = findViewById(R.id.listView);
mRecyclerViewTOP.setHasFixedSize(true);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
exampleAdapter = new ExampleAdapter(itemCassas);
mRecyclerViewTOP.setLayoutManager(mLayoutManager);
mRecyclerViewTOP.setAdapter(exampleAdapter);
// onSwipe();
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.RIGHT) {
customAllertDelete(position);
viewHolder.itemView.setBackgroundColor(Color.parseColor("#cc0000"));
exampleAdapter.notifyDataSetChanged();
}
if (direction == ItemTouchHelper.LEFT) {
customAllertQuantity(position);
}
}
}).attachToRecyclerView(mRecyclerViewTOP);
}
And here is also the Adapter code if it could be usefull
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> {
private ArrayList<ItemCassa> mExampleList;
#NonNull
#Override
public ExampleViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerlist_item,parent,false);
return new ExampleViewHolder(v);
}
ExampleAdapter(ArrayList<ItemCassa> exampleList){
mExampleList = exampleList;
}
#Override
public void onBindViewHolder(#NonNull ExampleViewHolder holder, int position) {
ItemCassa item = mExampleList.get(position);
holder.desc.setText(item.getBtnName());
holder.qta.setText(String.valueOf(item.getQuant()));
holder.imp.setText(String.valueOf((new DecimalFormat("#0.00").format(item.getPrice()))));
if(position % 2 == 0 ){
holder.itemView.setBackgroundColor(Color.parseColor("#C0C0C0"));
holder.desc.setBackgroundColor(Color.parseColor("#C0C0C0"));
holder.qta.setBackgroundColor(Color.parseColor("#C0C0C0"));
holder.imp.setBackgroundColor(Color.parseColor("#C0C0C0"));
}else if(position % 2 == 1){
holder.itemView.setBackgroundColor(Color.parseColor("#D3D3D3"));
holder.desc.setBackgroundColor(Color.parseColor("#D3D3D3"));
holder.qta.setBackgroundColor(Color.parseColor("#D3D3D3"));
holder.imp.setBackgroundColor(Color.parseColor("#D3D3D3"));
}
}
#Override
public int getItemCount() {
return mExampleList.size();
}
public static class ExampleViewHolder extends RecyclerView.ViewHolder {
public TextView desc;
public TextView qta;
public TextView imp;
ExampleViewHolder(View itemView) {
super(itemView);
desc = itemView.findViewById(R.id.Desc);
qta = itemView.findViewById(R.id.Qta);
imp = itemView.findViewById(R.id.Imp);
}
}
public void removeItem(int position) {
mExampleList.remove(position);
notifyItemRemoved(position);
}
}
Here is the gif that "explain" a bit what i'm trying to do, as you can see on swipe it's open an AlertDialog and turn back the selected item, but now i would color that selected item background until the user make a choose in the AlertDialog
Try using like this:
First of all in your onSwiped method call your adapter's method and pass the required parameters.
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
int swipedPosition = viewHolder.getAdapterPosition();
YourAdapter adapter = (YourAdapter) rlCartList.getAdapter();
adapter.remove(swipedPosition); // I was removing items so you
can change the name of method as you like
}
Now in your adapter do something like this:
public void remove(int position) {
YourModel item = cartItems.get(position);
if (cartItems.contains(item)) {
ViewHolder.tvItemName.setBackgroundColor(mContext.getResources().getColor(R.color.grey));
notifyDataSetChanged();
}
}
One more thing is you will need to make your textView or the view you are assigning the background to Static. And I have tested this code it's running fine in my project the background of textView changes on swipe.
Tell me if you need further assistance. And also one more thing you can use your alert dialog in adapter too :)
I want to swipe item from recyclerview and when item is swiped the bottom item should move up.
in onCreateView of my Fragment
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//Toast.makeText(getActivity(),"ByBy",Toast.LENGTH_LONG).show();
myListCursorAdapter.onItemRemove(viewHolder, recyclerView);
}
}).attachToRecyclerView(recyclerView);
in Adapter
public class TaskCursorAdapter extends RecyclerCursorAdapter<TaskCursorAdapter.ViewHolder> {
Context context;
Cursor cursor;
public TaskCursorAdapter(Context context, Cursor cursor) {
super(context, cursor);
this.cursor = cursor;
this.context = context;
setHasStableIds(true);
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView taskname;
public TextView dateDetails;
Context context;
Cursor cursor;
public ViewHolder(View view, Context context, Cursor cursor) {
super(view);
this.context = context;
this.cursor = cursor;
taskname = (TextView) view.findViewById(R.id.listitemtaskname);
dateDetails = (TextView) view.findViewById(R.id.listitemdatedetails);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// Form the content URI that represents the specific pet that was clicked on,
// by appending the "id" (passed as input to this method) onto the
// {#link PetEntry#CONTENT_URI}.
// For example, the URI would be "content://com.example.android.pets/pets/2"
// if the pet with ID 2 was clicked on.
Intent intent = new Intent(context, EditorActivity.class);
Uri currentPetUri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, this.getAdapterPosition() + 1);
intent.setData(currentPetUri);
context.startActivity(intent);
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view, context, cursor);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
int taskColumnIndex = cursor.getColumnIndex(TaskContract.TaskEntry.NAME);
int dateColumnIndex = cursor.getColumnIndex(TaskContract.TaskEntry.DUEDATE);
int timeColumnIndex = cursor.getColumnIndex(TaskContract.TaskEntry.DUETIME);
String task = cursor.getString(taskColumnIndex);
String dateString = cursor.getString(dateColumnIndex);
String timeString = cursor.getString(timeColumnIndex);
viewHolder.cursor = cursor;
viewHolder.taskname.setText(task);
if (timeString == null && dateString == null) {
viewHolder.dateDetails.setVisibility(View.GONE);
} else {
viewHolder.dateDetails.setText(dateString + "\t\t" + timeString);
}
}
public void onItemRemove(final RecyclerView.ViewHolder viewHolder, final RecyclerView recyclerView) {
int adapterPosition = viewHolder.getAdapterPosition()+1;
Uri currentPetUri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, viewHolder.getAdapterPosition());
Snackbar snackbar = Snackbar
.make(recyclerView, "PHOTO REMOVED", Snackbar.LENGTH_LONG)
.setAction("UNDO", new View.OnClickListener() {
#Override
public void onClick(View view) {
int mAdapterPosition = viewHolder.getAdapterPosition() + 1;
Toast.makeText(context,"Hi",Toast.LENGTH_LONG).show();
recyclerView.scrollToPosition(mAdapterPosition);
}
});
snackbar.show();
context.getContentResolver().insert(TaskContract.TaskEntry.CONTENT_URI_FINISHED, values);
// Toast.makeText(context,"Hi2",Toast.LENGTH_LONG).show();
//notifyItemChanged(adapterPosition);
recyclerView.scrollToPosition(adapterPosition);
}
}
I tried everything but its difficult to swipe item from recyclerview and when undo of snackbar is pressed i want that item to reappear.I want to swipe item from recyclerview and when item is swiped the bottom item should move up.
1) You need to override the method onSwiped() as below.
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.DOWN | ItemTouchHelper.UP) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//do something
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
int position = viewHolder.getAdapterPosition();
arrayList.remove(position);//remove swiped item
adapter.notifyDataSetChanged();//notify the recyclerview changes in the dataset
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(rv);//attach to your recyclerview
2) Don't forget to import v22.2.+ of the RecyclerView library.
3) For the botom item to move up(update) you need to do a refresh after "adapter.notifyDataSetChanged()" first update the database then pull the new data from the database(with changes). This will update the database and also the recyclerview.
4) To Undo you need to keep a stack of the elements that were removed(LIFO order) and insert them back as you click undo.
If you are using Content Provider you must call your cursor inside onSwiped method like this:
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(
0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return true;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
final int position = viewHolder.getLayoutPosition();
Cursor cursor = myListCursorAdapter.getCursor();
cursor.moveToPosition(x);
final long id = cursor.getLong(cursor.getColumnIndex(Your_Column_ID));
getActivity().getContentResolver().delete(Uri.withAppendedPath(YourContract.YOUR_URI, String.valueOf(id)), null, null);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(yourRecyclerView); //attach to your recyclerview
In your Adapter you must set getCursor():
public Cursor getCursor(){
return yourCursor;
}
I want to create sorting with animation on Android.
I think the best way is to make use of RecyclerView.
For better user experience I want to show some animation especially when there is a change in the position of the items in the RecyclerView
I think there are 2 types of animation to do.
1 Swap item e.g. bubbleSort
2 Shift items e.g. insertion sort
Here is what you want with sample code.
In your fragment or activity.
MyAdapter adapter = new MyAdapter(getActivity(), mDataSet);
ItemTouchHelper.Callback callback = new RecyclerItemTouchHelper(adapter);
ItemTouchHelper helper = new ItemTouchHelper(callback);
helper.attachToRecyclerView(mRecyclerView);
//Here mRecyclerView is ref of your RecyclerView & mDataSet is List of your data set.
Then here is the code of your Adapter.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private Context mContext;
private List<Object> mDataSet = new ArrayList<>();
//Replace Object with your data type
public MyAdapter(Context context, List<Object> dataSet) {
mContext = context;
mDataSet=dataSet;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_layout, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Object object = mDataSet.get(position);
//Do your Stuff
}
public void onMove(RecyclerView recyclerView, int firstPos, int secondPos) {
/*Do your stuff what you want
Notify your adapter about change in positions using notifyItemMoved method
Shift element e.g. insertion sort*/
}
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
/*Do your stuff what you want
Swap element e.g. bubbleSort*/
}
#Override
public int getItemCount() {
return mDataSet.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
CardView mCardView;
public ViewHolder(View itemView) {
super(itemView);
mCardView = (CardView) itemView.findViewById(R.id.card_view);
}
}
}
Here is the code of RecyclerItemTouchHelper.
public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
private MyAdapter mAdapter;
public RecyclerItemTouchHelper(SmartSocketAdapter adapter){
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
mAdapter = adapter;
}
#Override
public boolean onMove(final RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mAdapter.onMove(recyclerView,viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onSwiped(viewHolder, direction);
}
}
In this way you will get both call backs in your adapter, there your can notify your adapter about changes and you can have animation too using notifyItemMoved method.
Actually it's so easy now, maybe I'm answering too late, but for those who might still have the same question, you could use ListAdapter instead of RecyclerView.Adapter.
It handles the data itself. The only thing you have to add to it's constructor is a DiffUtil.ItemCallback implementing two functions to tell the adapter if the items are similar (to handle the transition when changing positions).
Have in mind, you have to implement it as static variable since you need to pass it to the constructor.
public class SampleAdapter extends ListAdapter<ListItem, BaseViewHolder> {
private static final DiffUtil.ItemCallback<ListItem> DIFF_CALLBACK =
new DiffUtil.ItemCallback<ListItem>() {
#Override
public boolean areItemsTheSame(#NonNull ListItem oldItem,
#NonNull ListItem newItem) {
return oldItem.getCode().equals(newItem.getCode()); //unique
}
#Override
public boolean areContentsTheSame(#NonNull ListItem oldItem,
#NonNull ListItem newItem) {
return oldItem.getName().equals(newItem.getName()) &&
oldItem.getIconUrl().equals(newItem.getIconUrl());
}
};
public SampleAdapter() {
super(DIFF_CALLBACK);
}
}
and the rest of the adapter is the same as your RecyclerView.Adapter.
The first function tells if they are identical. The second function tells the adapter if the contents of the identical items(before and after) are changed, for UI updating purposes.
And you can simply use this code to update your new list (with animation of changing position).
adapter.submitList(...)
Hope it works for you too...
An example of bubble sorting in Recyclerview with animation:
In Activity:
public class MainActivity extends AppCompatActivity {
private ArrayList mList = new ArrayList();
private RecyclerView recyclerView;
private CustomAdapter mAdapter;
private Button btnGenNumber, btnSort;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerview);
btnGenNumber = findViewById(R.id.btnGenNumber);
btnSort = findViewById(R.id.btnSort);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
//animation
final LayoutAnimationController controller =
AnimationUtils.loadLayoutAnimation(this, R.anim.layout_animation_fall_down);
recyclerView.setLayoutAnimation(controller);
mAdapter = new CustomAdapter(this, mList);
recyclerView.setAdapter(mAdapter);
btnGenNumber.setOnClickListener(view -> {
genNewNumbers();
});
btnSort.setOnClickListener(view -> {
sortList();
});
genNewNumbers();
}
private void sortList() {
//bubble sort
int n = mList.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if ((int) mList.get(j) > (int) mList.get(j + 1)) {
Collections.swap(mList, j, j + 1);
mAdapter.notifyItemMoved(j, j + 1);
}
}
}
}
private void genNewNumbers() {
mList.clear();
Random rand = new Random();
for (int i = 0; i < 5; i++) {
int int_random = rand.nextInt(10);//0-9
mList.add(int_random);
}
//reapply animation
final LayoutAnimationController controller =
AnimationUtils.loadLayoutAnimation(this, R.anim.layout_animation_fall_down);
recyclerView.setLayoutAnimation(controller);
recyclerView.scheduleLayoutAnimation();
//update list
mAdapter.setList(mList);
}
}
In Adapter:
public void setList(ArrayList list) {
this.localDataSet = list;
notifyDataSetChanged();
}
I have an ArrayList<String> with 6 items {"1", "2", "3", "4", "5", "6"}.
I am representing these items with a CardView. I want to remove the items with swiping left.
It looks like this: http://imgur.com/cuWoiB3
When I swipe right from number 2, it looks like this: http://imgur.com/5E9fwP0
If I remove Number 5, it removes number 2. If I remove number 3, it removes number 1. It seems to be completely random.
Am I missing something here? How do I fix this?
Relevant code:
My adapter:
public class ChoresAdapter extends RecyclerView.Adapter<ChoresAdapter.ChoreViewHolder>{
private ArrayList<String> chores;
public ChoresAdapter(ArrayList<String> chores){
this.chores = chores;
}
#Override
public ChoreViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_cardview, parent, false);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
ChoreViewHolder pvh = new ChoreViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(ChoreViewHolder holder, int position) {
holder.choreName.setText(this.chores.get(position));
}
#Override
public int getItemCount() {
return this.chores.size();
}
public void removeAt(int position) {
this.chores.remove(position);
notifyItemRemoved(position);
notifyDataSetChanged();
}
public static class ChoreViewHolder extends RecyclerView.ViewHolder {
CardView cv;
public static TextView choreName;
public static TextView personAge;
public static ImageView personPhoto;
ChoreViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
choreName = (TextView)itemView.findViewById(R.id.chore_name);
}
}
}
Relevant code in my fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_chores, container, false);
RecyclerView rv = (RecyclerView)view.findViewById(R.id.rv);
rv.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
chores = new ArrayList<>();
chores.add("1");
chores.add("2");
chores.add("3");
chores.add("4");
chores.add("5");
chores.add("6");
adapter = new ChoresAdapter(chores);
SwipeableRecyclerViewTouchListener swipeTouchListener =
new SwipeableRecyclerViewTouchListener(rv,
new SwipeableRecyclerViewTouchListener.SwipeListener() {
#Override
public boolean canSwipe(int position) {
return true;
}
#Override
public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
adapter.removeAt(position);
}
}
#Override
public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
adapter.removeAt(position);
}
}
});
rv.addOnItemTouchListener(swipeTouchListener);
rv.setAdapter(adapter);
return view;
}
Its bit late, I just fall into the same situation and got answer, Just use
chores.remove(position);
adapter.notifyDataSetChanged();
You dont need to do that on the adapter class.
You can use below code (ItemTouchHelper.SimpleCallback from Android support V7) to remove the cards from RecyclerView using swipe gesture. You need to remove element from your ArrayList as well when you swipe it from RecyclerView.
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
chores.remove(viewHolder.getAdapterPosition());
adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
}
#Override
public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recList);