how to set itemTouchHelper swipe selectively? - android

so i have implemented this itemtouchhelper.simple callback on a recyclerview rv.
now in this rv i have set 2 kinds on layout as a row depending on the content type.
so as i set this touchhelper on the rv it is being implemented on both of these layouts even though i did'nt want to do that.i only want to apply that swipe to only one type of this layout.
ItemTouchHelper.SimpleCallback ith = new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder viewHolder1) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
if(viewHolder.itemView.findViewById(R.id.messageholder_from) != null)
{
Log.d("texts", "onSwiped: "+viewHolder.itemView.findViewById(R.id.messageholder_from).findViewById(R.id.crfrom));
}
adapter.notifyDataSetChanged();
}
};
new ItemTouchHelper(ith).attachToRecyclerView(rv);
as you can see this code i only want to implement the swipe on the row which has this messageholder_from child in it otherwise i don't want to implement the swipe.
is there any way to remove the swipe animation and the listener on this other child messageholder_to.
my app shows either a to_layout or a from_layout depending on he message id.
thanks for any kind of help.

Inside your ItemTouchHelper.SimpleCallback, override the getSwipeDirs() method and return 0 for any row that you want to disable swiping on.
#Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder.itemView.findViewById(R.id.messageholder_from) == null) {
return 0;
}
return super.getSwipeDirs(recyclerView, viewHolder);
}
Depending on exactly how your app is set up, there might be a better way to detect that viewHolder is the kind you want to disallow swiping on. For example, maybe you could have
if (viewHolder instanceof WrongKindOfViewHolder)
or
if (viewHolder.isNotSwipeable)

int makeMovementFlags (int dragFlags,int swipeFlags) is responsible for each row move, swipe or drag.
From documentation :
Convenience method to create movement flags.
For instance, if you want to let your items be drag & dropped
vertically and swiped left to be dismissed, you can call this method
with: makeMovementFlags(UP | DOWN, LEFT);
Implement getMovementFlags() method and return with makeMovementFlags(0, 0); for which row or viewholder you don't want to add swipe or drag.
Example Code:
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;
int swipeFlags = 0;
if (recyclerView.getLayoutManager().getClass() == LinearLayoutManager.class ) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int orientation = linearLayoutManager.getOrientation();
if (orientation == LinearLayoutManager.VERTICAL) {
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
}else {
// horizontal
dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
// no swipe for horizontal layout
swipeFlags = 0;
}
}
if (viewHolder.getAdapterPosition() == 3) {
// disable swipe feature for position 3
return makeMovementFlags(0, 0);
}
return makeMovementFlags(dragFlags, swipeFlags);
}

Related

In Android 10, the RecyclerView item drag-and-swap method is difficult to trigger (ItemTouchHelper.callback onMove)

This is my implementation of ItemTouchHelper.callback
I implemented getMovementFlags so that it could drag and drop in UP, Down, left, and right directions but didn't execute the onMove method
I know where the problem is because I'm in the setOnLongClickListener notifyDataSetChanged on the item and that causes it to fail to drag but I do need to go through setOnLongClickListener, okay NotifyDataSetChanged updates the item to editable style
#Override
public int getMovementFlags(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
dragAdapter.itemMove(fromPosition, toPosition);
return true;
}
LEFT and RIGHT should be used for swipe, so keep UP and DOWN only for move position.
And, onMove will be called many many times, so you should implement clearView and do the move in clearView. onMove is just used to record positions.
private val _callback = object:ItemTouchHelper.Callback() {
override fun getMovementFlags(rv: RecyclerView, h: RecyclerView.ViewHolder): Int {
val drag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
val pos = h.layoutPosition
val swipe = if (pos == _a._current) 0 else ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT // don't allow swipe current row
return makeMovementFlags(drag, swipe)
}
// onMove will be called many many times if dragging toward top/bottom
// to avoid this, make real swap at clearView which will be called only once
private var _moveFrom = -1
private var _moveTo = -1
override fun onMove(rv: RecyclerView, h: RecyclerView.ViewHolder, dst: RecyclerView.ViewHolder): Boolean {
if (_moveFrom == -1) {
_moveFrom = h.layoutPosition
}
_moveTo = dst.layoutPosition
return true
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
if (_moveFrom >= 0 && _moveTo >= 0 && _moveFrom != _moveTo) {
_layers.removeAt(_moveFrom)
_layers.add(_moveTo, layer)
if (_moveFrom < _moveTo) { // drag down
...
} else { // drag up
...
}
}
_moveFrom = -1
_moveTo = -1
Handler(Looper.getMainLooper()).post { _adapter.notifyDataSetChanged() }
}
}

ItemTouchHelper for Horizontal RecyclerView

I am trying to implement ItemTouchHelper for Horizontal Recyclerview. (setting layout manager to LinearLayoutManager with orientation LinearLayoutManager.HORIZONTAL). Example, I want to delete an item when swiped down and drag to left or right for swapping items.
All the samples I have gone through explains ItemTouchHelper for Vertical Recyclerview or items in grid.
Followed samples from following links:
https://medium.com/#ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf
https://medium.com/#xabaras/recyclerview-swiping-with-style-151e21b1af07
How can I achieve swipe down to delete and drag sideways to swap items in Horizontal Recyclerview?
You can use this simple code to achieve the swipe down to remove.
ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.DOWN) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
final int position = viewHolder.getLayoutPosition();
if (direction == ItemTouchHelper.DOWN) {
//your code for deleting the item from database or from the list
adapter.removeNote(position);
adapter.notifyItemRemoved(position)
}
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
For Kotlin geeks below is the code for the same -
val simpleCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.DOWN) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
if (direction == ItemTouchHelper.DOWN) {
//your code for deleting the item from database or from the list
val position = viewHolder.adapterPosition
noteList.removeAt(position)
adapter.notifyItemRemoved(position)
}
}
}
val itemTouchHelper = ItemTouchHelper(simpleCallback)
itemTouchHelper.attachToRecyclerView(recycler_view)
You only need to change the method "getMovementFlags".
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
to
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
final int swipeFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int dragFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
To delete an item, create a new method in "ItemTouchHelperAdapter" called "onSwiped" and implement it to remove the item
#Override
public boolean onSwiped(int itemPosition, int direction) {
if(direction == SimpleItemTouchHelperCallback.SWIPED_TO_END) {
list.remove(itemPosition);
notifyItemRemoved(itemPosition);
}else{
notifyItemChanged(itemPosition);
}
return true;
}

ItemTouchHelper with SpannedGridLayoutManager - RecyclerView issues

I am facing an issue with ItemTouchHelper in combination with SpannedGridLayoutManager in my RecyclerView, drag is ended prematurely when dragging to the item next to the dragged one. I know it is glitchy layout manager, because it works with other layout managers without any issues.
Did somebody worked this out already?
The onSelectedChanged(RecyclerView.ViewHolder, int) callback provides information about the current actionState:
- ACTION_STATE_IDLE:
- ACTION_STATE_DRAG
- ACTION_STATE_SWIPE
So you could keep track whether the order changed, and when the state changes to ACTION_STATE_IDLE, you can do what you need to do!
Implement a callback class like this.
class CardsTouchHelperCallback extends ItemTouchHelper.Callback {
...
#Override
public boolean onMove(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
dragFrom = fromPosition;
dragTo = toPosition;
mOrderChanged = true;
return false;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE && mOrderChanged) {
//doSomething();
touchHelperAdapter.onItemMove(dragFrom, dragTo);
mOrderChanged = false;
}
}
}

Custom swipe ItemTouchHelper

Hi i have add ItemTouchHelper to my listview and i have do MyItemTouchHelper.attachToRecyclerView(myRecyclerView), then i have implements code for swipe to right:
private ItemTouchHelper itemTouchHelperEventi = 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 swipeDir) {
Evento ev = lista_eventi.get(viewHolder.getAdapterPosition());
analizzaEvento = new AnalizzaEvento(ev.getNome_evento());
adapterRecyclerViewEventi.remove(positionForResult);
adapterRecyclerViewEventi.notifyDataSetChanged();
}
});
Now i want to implement swipe code to remove item how gmail, i want that when i swipe to right background row becomes red and at left of row there is label undo and at right of row there is label delete (or confirm) if i click on right i delete item if i click on left return to the previous situation.
Please don't link other library i want to add this festure at my code without using external library, i don't want to rewrite all code only for this feature.
Is it possible?
Here is sample code
ItemTouchHelper.Callback simpleItemTouchCallback=new ItemTouchHelper.Callback() {
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//Unlock the movement of the item
//If you want only left to right unlock that moment only
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags;
if(viewHolder instanceof HeterogenousAdapter.ImageViewHolder)
swipeFlags = ItemTouchHelper.ANIMATION_TYPE_SWIPE_CANCEL ;
else
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END ;
return makeMovementFlags(dragFlags, swipeFlags);
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//when user swiped this method getting call
int position = viewHolder.getAdapterPosition();
if (direction == ItemTouchHelper.LEFT){
adapter.removeItem(position);
}else {
removeView();
edit_position = position;
alertDialog.setTitle("Edit Country");
if (objectsArrayList.get(position) instanceof UserInfo){
UserInfo userInfo= (UserInfo) objectsArrayList.get(position);
et_country.setText(userInfo.getFirstName());
}else {
String abc= (String) objectsArrayList.get(position);
et_country.setText("ESHVAR");
}
alertDialog.show();
}
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//when swiped started what you wants to do
//Here you can set Red color with icon on it
Bitmap icon;
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
View itemView = viewHolder.itemView;
float height=(float) itemView.getBottom() - (float) itemView.getTop();
float width =height/3;
if (dX > 0){
paint.setColor(Color.parseColor("#388e3c"));
RectF background = new RectF(
(float)itemView.getLeft(),
(float)itemView.getTop(),
dX,
(float)itemView.getBottom());
c.drawRect(background,paint);
icon = BitmapFactory.decodeResource(getResources(),R.drawable.action_search);
RectF icon_dest = new RectF(
(float)itemView.getLeft()+width,
itemView.getTop()+width,
(float)itemView.getLeft()+2*width,
(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,paint);
}else {
paint.setColor(Color.parseColor("#d32f2f"));
RectF background = new RectF(
(float)itemView.getRight()+dX,
(float)itemView.getTop(),
(float)itemView.getRight(),
(float)itemView.getBottom());
c.drawRect(background,paint);
icon =BitmapFactory.decodeResource(getResources(),R.drawable.action_search);
RectF icon_dest=new RectF(
(float)itemView.getRight()-2*width,
(float)itemView.getTop()+width,
(float)itemView.getRight() - width,
(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,paint);
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
};
//Adding Recycle view to Item touch helper
ItemTouchHelper itemTouchHelper=new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);

Recyclerview swipe direction right

I was wondering if you could use the itemtouchhelper to dismiss items , ONLY when user swipes to right? I'm using this code, but the direction does not work
public class CrimeTouchHelper extends ItemTouchHelper.SimpleCallback {
private CrimeAdapter mMovieAdapter;
public CrimeTouchHelper(CrimeAdapter movieAdapter){
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
this.mMovieAdapter = movieAdapter;
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//TODO: Not implemented here
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//Remove item
Log.e("DIRECTION", direction + "");
if(direction == 8) {
mMovieAdapter.remove(viewHolder.getAdapterPosition());
}
}
}`
This is simple to do. You can use this code,
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new
ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(
final RecyclerView recyclerView,
final RecyclerView.ViewHolder viewHolder,
final RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(
final RecyclerView.ViewHolder viewHolder,
final int swipeDir) {
adapter.remove(viewHolder.getAdapterPosition());
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(
simpleItemTouchCallback
);
itemTouchHelper.attachToRecyclerView(itemsRecyclerView);
You can pass ItemTouchHelper.RIGHT as the second parameter of the constructor which actaully takes the direction.
Use the onSwipe() method to perform the operation you want to do, like removing the item from the adapter.
Hope this helps. Do let me know if you face any problem with it.
Set it in the super method in the constructor of CrimeTouchHelper.
The second parameter is swipe directions, so just pass ItemTouchHelper.RIGHT
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT);
After that, you can remove the 'if' check in #onSwiped
Your current if check in #onSwiped will not prevent the swipe. Assuming 8 is the int value for swiping right, all you're doing now is preventing the adapter from removing the item (but that item will still visually be swiped away).
You should override getMovementFlags method and set swipe flag to ItemTouchHelper.START in your customItemTouchHelper.Callback class
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// Set movement flags based on the layout manager
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
} else {
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
This will block the swipe from left to right.To do the opposite direction set flag to ItemTouchHelper.END

Categories

Resources