I'm trying to create a view that can be swiped to dismiss, but it can be undone. The items have a background and a foreground inside a FrameView
. I'm overriding onChildDraw
in ItemTouchHelper.Callback
like this:
@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) {
if (viewHolder instanceof ItemViewHolder) {
ItemViewHolder holder = (ItemViewHolder) viewHolder;
holder.foreground.setTranslationX(dX);
}
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
Everything works, untill I try to undo the swipe action based on user actions like this:
foreground.animate()
.translationX(0)
.setDuration(150);
which does bring the actual view back to its position, but if the user tries to swipe that item again, the background is shown again, and for some reason onChildDraw is called with dX parameter greater than the width of the screen. Tapping on the item reveals the background view for a split second, then the foreground can be normally dismissed. How can I fix this?
The solution was to use getDefaultUIUtil()
function of ItemTouchHelper.Callback
. The working code is as following:
@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) {
if (viewHolder instanceof TrackerListAdapter.ItemViewHolder) {
TrackerListAdapter.ItemViewHolder holder =
(TrackerListAdapter.ItemViewHolder) viewHolder;
getDefaultUIUtil().onDraw(c, recyclerView, holder.foreground, dX, dY, actionState, isCurrentlyActive);
}
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}