1

I have a recyclerview and I've add swipe to it with itemtouchhelper class and it works fine, there is 2 views in layout that foreground view moves on swipe over bacjground layer, problem is I want to foreground view get the previous location after swipe , like swipe effect that make call in Samsung phones. I can make that with calling notifyitemchanged after swipe. but I works one time and if I swipe again on that item, view is not restored this is my itemtouchhelper class

public class RecyclerItemTouchHelperlog extends ItemTouchHelper.SimpleCallback {
private RecyclerItemTouchHelperListener listener;

public RecyclerItemTouchHelperlog(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
    super(dragDirs, swipeDirs);
    this.listener = listener;
}

@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
    return true;
}

@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
    if (viewHolder != null) {
        final View foregroundView = ((recycleAdapterlog.MyViewHolder) viewHolder).logitm;

        getDefaultUIUtil().onSelected(foregroundView);
    }
}

@Override
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
                            RecyclerView.ViewHolder viewHolder, float dX, float dY,
                            int actionState, boolean isCurrentlyActive) {
    final View foregroundView = ((recycleAdapterlog.MyViewHolder) viewHolder).logitm;
    getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
            actionState, isCurrentlyActive);
}

@Override
public void clearView(@NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    final View foregroundView = ((recycleAdapterlog.MyViewHolder) viewHolder).logitm;
    getDefaultUIUtil().clearView(foregroundView);
}

@Override
public int getSwipeDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {

    View hv=((recycleAdapterlog.MyViewHolder) viewHolder).hv;
    if(hv==null)return super.getSwipeDirs(recyclerView, viewHolder);
    else if(hv.getVisibility()==View.VISIBLE)return 0;
    else return super.getSwipeDirs(recyclerView, viewHolder);


}

@Override
public void onChildDraw(Canvas c, @NonNull RecyclerView recyclerView,
                        @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY,
                        int actionState, boolean isCurrentlyActive) {
    final View foregroundView = ((recycleAdapterlog.MyViewHolder) viewHolder).logitm;
    final View swipel = ((recycleAdapterlog.MyViewHolder) viewHolder).swipelogleft;
    final View swiper = ((recycleAdapterlog.MyViewHolder) viewHolder).swipelogright;
    if(dX<0){
        swipel.setVisibility(View.VISIBLE);
        swiper.setVisibility(View.GONE);
    }
    else {
        swipel.setVisibility(View.GONE);
        swiper.setVisibility(View.VISIBLE);
    }
    if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
        final Float alpha =1 - Math.abs (dX) / ( viewHolder.itemView.getWidth ());
        foregroundView.setAlpha (alpha);
        foregroundView.setTranslationX (dX);
    }

    recentconfrag.swipedlog=true;

    getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
            actionState, isCurrentlyActive);
}

@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
    listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());


}

@Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
    return super.convertToAbsoluteDirection(flags, layoutDirection);
}

public interface RecyclerItemTouchHelperListener {
    void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);

}

}

saber javadi
  • 473
  • 1
  • 7
  • 17
  • 1
    I use https://stackoverflow.com/questions/31787272/android-recyclerview-itemtouchhelper-revert-swipe-and-restore-view-holder (`notifyItemChanged`) and everything works (swiping and reverting the second time also works). I also use `RecyclerItemTouchHelper` similar to yours, without `getSwipeDirs`, and `onChildDraw` is different. I will add it below. – CoolMind Sep 19 '19 at 07:13
  • 1
    Possible duplicate of [Android RecyclerView ItemTouchHelper revert swipe and restore view holder](https://stackoverflow.com/questions/31787272/android-recyclerview-itemtouchhelper-revert-swipe-and-restore-view-holder) – denvercoder9 Sep 19 '19 at 12:56

1 Answers1

1

I don't know, where is a problem, I tested the solution below on emulator and Samsung Galaxy S4.

public class RecyclerItemTouchHelper extends ItemTouchHelper.SimpleCallback {
    private RecyclerItemTouchHelperListener listener;

    public RecyclerItemTouchHelper(int dragDirs, int swipeDirs, RecyclerItemTouchHelperListener listener) {
        super(dragDirs, swipeDirs);
        this.listener = listener;
    }

    @Override
    public boolean onMove(@NotNull RecyclerView recyclerView,
                          @NotNull RecyclerView.ViewHolder viewHolder,
                          @NotNull RecyclerView.ViewHolder target) {
        return true;
    }

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (viewHolder instanceof YourAdapter.ItemViewHolder) {
            final View foregroundView = ((YourAdapter.ItemViewHolder) viewHolder).getItem();
            getDefaultUIUtil().onSelected(foregroundView);
        }
    }

    @Override
    public void onChildDrawOver(@NotNull Canvas c, @NotNull RecyclerView recyclerView,
                                @NotNull RecyclerView.ViewHolder viewHolder, float dX, float dY,
                                int actionState, boolean isCurrentlyActive) {
        if (viewHolder instanceof YourAdapter.ItemViewHolder) {
            final View foregroundView = ((YourAdapter.ItemViewHolder) viewHolder).getItem();
            getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
                actionState, isCurrentlyActive);
        }
    }

    @Override
    public void clearView(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder) {
        if (viewHolder instanceof YourAdapter.ItemViewHolder) {
            final View foregroundView = ((YourAdapter.ItemViewHolder) viewHolder).getItem();
            getDefaultUIUtil().clearView(foregroundView);
        }
    }

    @Override
    public void onChildDraw(@NotNull Canvas c, @NotNull RecyclerView recyclerView,
                            @NotNull RecyclerView.ViewHolder viewHolder, float dX, float dY,
                            int actionState, boolean isCurrentlyActive) {
        if (viewHolder instanceof YourAdapter.ItemViewHolder) {
            final View foregroundView = ((YourAdapter.ItemViewHolder) viewHolder).getItem();
            getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
                actionState, isCurrentlyActive);
        }
    }

    @Override
    public void onSwiped(@NotNull RecyclerView.ViewHolder viewHolder, int direction) {
        listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
    }

    public interface RecyclerItemTouchHelperListener {
        void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
    }
}

Then use it in a fragment.

class YourFragment : Fragment(), RecyclerItemTouchHelper.RecyclerItemTouchHelperListener {

    private var adapter: YourAdapter? = null
    private lateinit var itemTouchHelperCallback: RecyclerItemTouchHelper


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(LAYOUT, container, false)

        adapter = YourAdapter(this)

        view.recycler_view.run {
            layoutManager = LinearLayoutManager(context)
            adapter = this@YourFragment.adapter
            setHasFixedSize(true)
            // attaching the touch helper to recycler view
            itemTouchHelperCallback =
                RecyclerItemTouchHelper(0, ItemTouchHelper.LEFT, this@YourFragment)
            ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(this)
        }

        return view
    }

    // callback when recycler view is swiped
    // item will be removed on swiped
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder?, direction: Int, position: Int) {
        // if (viewHolder is YourAdapter.ItemViewHolder) {
            // remove the item from recycler view
            // This is a custom dialog with "Yes", "No" buttons.
            showDialog("Remove the item?",
                { adapter?.removeAt(position) },
                { adapter?.notifyItemChanged(position) })
        // }
    }

Notice that I use position in onSwiped, but viewHolder.getAdapterPosition() is also right. I used a solution for reverting an item from Android RecyclerView ItemTouchHelper revert swipe and restore view holder.

CoolMind
  • 26,736
  • 15
  • 188
  • 224