How to use ItemTouchHelper and its Callback or implement customized ones?

ywwynm picture ywwynm · Jun 11, 2015 · Viewed 9k times · Source

I noticed these libraries and was eager to use them in my app. My RecyclerView uses StaggeredGridLayoutManager to organize viewHolders and I've written down the following code:

ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
            ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END,
            ItemTouchHelper.START | ItemTouchHelper.END) {
        @Override
        public boolean onMove(RecyclerView recyclerView,
                              RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            mAdapter.move(viewHolder.getAdapterPosition(), target.getAdapterPosition());
            return true;
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            mAdapter.remove(viewHolder.getAdapterPosition());
        }
    });
    helper.attachToRecyclerView(mRecyclerView);

There are two problems:

  1. Swiping an item won't change its alpha by deltaX.

  2. Imagine that there are 3 items in the RecyclerView (which has 2 columns):

    • the first is a middle-size one;
    • the second is smaller than the first one;
    • the third is the biggest.

If I move the third one to the first place, scroll the RecyclerView down (other items won't influence the first 3 ones) and then up, the second one and the third one will be totally the same.

It seems that I should write a customized ItemTouchHelper to add alpha animation to solve the first problem and that I didn't use these classes correctly and thus caused the second problem.

As a result, what is the best sample for using ItemTouchHelper? Or how to implement a customized one? Thanks in advance for any answers or comments.

Answer

prodaea picture prodaea · Jun 29, 2015

According to the comments in ItemTouchHelper.Callback you want to override the methods onChildDraw or onChildDrawOver for those dX, dY values.

Also see getDefaultUIUtil and the implementations of ItemTouchUIUtil (which is what onChildDraw and onChildDrawOver call). The comment of getDefaultUIUtil demonstrates how to use it in conjunction with overriding onChildDraw and onChildDrawOver (even though the examples erroneously return a bool value for being handled).

Here's a quick example if you want to add 5 to the default elevation in Lollipop:

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

        if (Build.VERSION.SDK_INT >= 21 && isCurrentlyActive && !isElevated) {
            final float newElevation = 5f + ViewCompat.getElevation(viewHolder.itemView);
            ViewCompat.setElevation(viewHolder.itemView, newElevation);
            isElevated = true;
        }
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        isElevated = false;
    }