Recyclerview swipe direction right - android

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

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() }
}
}

where to write callback function for ItemTouchHelper which is used with RecyclerView

I want to write a piece of code into where item drag-drop is over. I got this answer https://stackoverflow.com/a/36275415/1684778 but I am confused about how to achieve this(where i have to implement that answer)
I want to write onDrop instead of onItemMove, how to achieve it.
DragItemTouchHelper
public class DragItemTouchHelper extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private final MoveHelperAdapter mAdapter;
public DragItemTouchHelper(MoveHelperAdapter adapter) {
mAdapter = adapter;
}
#Override
public boolean isLongPressDragEnabled() {
return true;
}
#Override
public boolean isItemViewSwipeEnabled() {
return false;
}
#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 | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
if (source.getItemViewType() != target.getItemViewType()) {
return false;
}
// Notify the adapter of the move
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
// Fade out the view as it is swiped out of the parent's bounds
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
viewHolder.itemView.setTranslationX(dX);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// We only want the active item to change
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
if (viewHolder instanceof TouchViewHolder) {
// Let the view holder know that this item is being moved or dragged
TouchViewHolder itemViewHolder = (TouchViewHolder) viewHolder;
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
#Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA_FULL);
if (viewHolder instanceof TouchViewHolder) {
// Tell the view holder it's time to restore the idle state
TouchViewHolder itemViewHolder = (TouchViewHolder) viewHolder;
itemViewHolder.onItemClear();
}
}
public interface MoveHelperAdapter {
boolean onItemMove(int fromPosition, int toPosition);
}
public interface TouchViewHolder {
void onItemSelected();
void onItemClear();
}
}
You can put your class that extends ItemTouchHelper callback in the end of the activity class where your RecyclerView is and attach it to RecyclerView defined in activity or fragment as below
ItemTouchHelper touchHelper = new ItemTouchHelper(your_custom_callback);
touchHelper.attachToRecyclerView(recyclerView);

how to set itemTouchHelper swipe selectively?

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);
}

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;
}

how to create drag and drop in recyclerview without drag header and footer?

I created drag and drop in recylerview using ItemTouchHelper.Callback,it is working.But i have header and footer in recylerview i dont want to drag header and footer.how to solve this,this is my code
recylerviewActivity
ItemTouchHelper.Callback callback = new SwipeAndDrag(pick_up_mAdapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerView);
SwipeAndDrag.java
public class SwipeAndDrag extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter mAdapter;
private RouteInformation points;
public SwipeAndDrag(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
#Override
public boolean isLongPressDragEnabled() {
return false;
}
#Override
public boolean isItemViewSwipeEnabled() {
return true;
}
#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);
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}
You should modify your getMovementFlags method like this (tested it and it seems ok) :
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder){
if(viewHolder instanceof yourFooterOrHeaderViewholderClass){
int dragFlags = 0; // then, they can't be dragged
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}else{ // if(viewHolder instanceof yourNormalItemViewHolderClass)
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
Then, only your items should be drag&dropped, whereas your header and footer couldn't be manually moved.

Categories

Resources