RecyclerView之item左滑喜欢右滑不喜欢~

话不多说,直接上图,看看是不是你的菜~

列表左右滑

参考:https://github.com/ehanxuan/Android-ItemTouchHelper-Demo

ItemTouchHelper

了解RecyclerView的同学都知道,item的操作都是通过ItemTouchHelper来处理的。
ItemTouchHelper用法很简单,初始化,然后绑定RecyclerView即可

        ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(like_me_list);

注意到ItemTouchHelper初始化时的参数了吗?
其实这个callback就是ItemTouchHelper.Callback,ItemTouchHelper.Callback是对item操作的回调类,比如item的move swipe等。

要想定制化我们的左右滑,最重要的就是重写ItemTouchHelper.Callback

ItemTouchHelper.Callback

实现如上GIF的效果

  1. 点击时,所点击的view要提到顶部(不然会被其他的item遮盖)
  2. 根据滑动的轨迹,让item按照需要的轨迹移动
  3. 移动的参数,移动后的处理

点击时,所点击的view要提到顶部

参考了源码,长按拖动时,item就是提到顶部的。

    public static void takeViewTopInRec(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, boolean isCurrentlyActive) {
        if (Build.VERSION.SDK_INT >= 21 && isCurrentlyActive) {
            Object originalElevation = viewHolder.itemView.getTag(android.support.v7.recyclerview.R.id.item_touch_helper_previous_elevation);
            if (originalElevation == null) {
                originalElevation = ViewCompat.getElevation(viewHolder.itemView);
                float newElevation = 1.0F + findMaxElevation(recyclerView, viewHolder.itemView);
                ViewCompat.setElevation(viewHolder.itemView, newElevation);
                viewHolder.itemView.setTag(android.support.v7.recyclerview.R.id.item_touch_helper_previous_elevation, originalElevation);
            }
        }
    }

    private static float findMaxElevation(RecyclerView recyclerView, View itemView) {
        int childCount = recyclerView.getChildCount();
        float max = 0.0F;

        for (int i = 0; i < childCount; ++i) {
            View child = recyclerView.getChildAt(i);
            if (child != itemView) {
                float elevation = ViewCompat.getElevation(child);
                if (elevation > max) {
                    max = elevation;
                }
            }
        }

        return max;
    }

根据滑动的轨迹,让item按照需要的轨迹移动

@Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {

            //为了把view提到顶部
            takeViewTopInRec(recyclerView, viewHolder, isCurrentlyActive);

            final int width = viewHolder.itemView.getWidth();
            final int height = viewHolder.itemView.getHeight();
            // Fade out the view as it is swiped out of the parent's bounds
            final float r = Math.abs(dX) / (float) width;

            final float alpha = ALPHA_FULL - r;

            viewHolder.itemView.setTranslationX(dX * 1.1f);

            if (r < 0.3) {
                viewHolder.itemView.setScaleX(1 + r * 0.2f);
                viewHolder.itemView.setScaleY(1 + r * 0.2f);
            }

            viewHolder.itemView.setTranslationY(r * height * 0.2f);
            if (dX >= 0) {
                swipeAction = MatchPairConstant.LIKE_ACTION;
                viewHolder.itemView.setRotation(10 * r);
                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).like.setAlpha(r * 4f > 1 ? 1f : r * 4f);
                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).dislike.setAlpha(0f);

            } else {
                swipeAction = MatchPairConstant.DIS_LIKE_ACTION;
                viewHolder.itemView.setRotation(-10 * r);

                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).dislike.setAlpha(r * 4f > 1 ? 1f : r * 4f);
                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).like.setAlpha(0f);
            }
            /*if (r > 0.5) {
                viewHolder.itemView.setAlpha(alpha * 2f);
            }*/

        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    }

移动的参数,移动后的处理

//滑动到删除的速度
    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return super.getSwipeEscapeVelocity(defaultValue);
    }

    @Override
    public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
        return 400;
        //return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
    }

    //滑动到删除的距离
    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        //return super.getSwipeThreshold(viewHolder);
        return 0.30f;
    }

    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setAlpha(ALPHA_FULL);
        viewHolder.itemView.setRotation(0);
        viewHolder.itemView.setTranslationX(0);
        viewHolder.itemView.setTranslationY(0);
        viewHolder.itemView.setScaleX(1);
        viewHolder.itemView.setScaleY(1);
        ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).like.setAlpha(0f);
        ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).dislike.setAlpha(0f);
        // Tell the view holder it's time to restore the idle state
        ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
        itemViewHolder.onItemClear();
    }
//支持滑动的模式(左右)
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        // Set movement flags based on the layout manager
        final int dragFlags = 0;
        final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

上面的代码就是核心了,但是还不足以让程序跑起来。我们要把某些行为(选中了item/移除了item/item移除后重置等)通知业务层

ItemTouchHelperAdapter

public interface ItemTouchHelperAdapter {

    /**
     * Called when an item has been dragged far enough to trigger a move. This is called every time
     * an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
     * <br/>
     * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
     * adjusting the underlying data to reflect this move.
     *
     * @param fromPosition The start position of the moved item.
     * @param toPosition   Then resolved position of the moved item.
     * @return True if the item was moved to the new adapter position.
     * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
     * @see RecyclerView.ViewHolder#getAdapterPosition()
     */
    boolean onItemMove(int fromPosition, int toPosition);


    /**
     * Called when an item has been dismissed by a swipe.<br/>
     * <br/>
     * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
     * adjusting the underlying data to reflect this removal.
     *
     * @param position The position of the item dismissed.
     * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
     * @see RecyclerView.ViewHolder#getAdapterPosition()
     */
    void onItemDismiss(String action, int position);

    void onItemReset(@NonNull RecyclerView.ViewHolder viewHolder, int position);
}
public interface ItemTouchHelperViewHolder {

    /**
     * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
     * Implementations should update the item view to indicate it's active state.
     */
    void onItemSelected();


    /**
     * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
     * state should be cleared.
     */
    void onItemClear();
}

实现了ItemTouchHelperAdapter的自定义apapter ,重写这些方法即可

@Override
    public void onItemDismiss(String action, int position) {
        final LikeMeDetailEntity likeMeDetailEntity = mItems.get(position);
        mItems.remove(position);
        notifyItemRemoved(position);
        if (mExecuteListener != null) {
            mExecuteListener.onLikeActionCallback(position, likeMeDetailEntity, action);
        }
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        Collections.swap(mItems, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    @Override
    public void onItemReset(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
        //notifyDataSetChanged();
        ToastUtils.showToast(GlobalContext.getString(R.string.no_like_me_like_time));
        notifyItemChanged(position);
    }

当然,还要支持点击右滑

private void swipeRight(final LikeMeDetailEntity detailEntity, ItemViewHolder holder, final int position) {
        clearAnim();
        final int widthPixels = GlobalContext.getDisplayMetrics().widthPixels;
        if (mExecuteListener != null) {
            mExecuteListener.onLikeAnimExecuteListener(LikeExecuteListener.START);
        }
        LikeMeItemTouchHelperCallback.takeViewTopInRec(recyclerView, holder, true);

        final View itemView = holder.itemView;
        final View like = holder.like;
        ValueAnimator rotation = ObjectAnimator.ofPropertyValuesHolder(
                itemView, PropertyValuesHolder.ofFloat("rotation", 30f));
        rotation.setDuration(300);
        float trans = itemView.getWidth() + widthPixels;
        ValueAnimator translateX = ObjectAnimator.ofPropertyValuesHolder(
                itemView, PropertyValuesHolder.ofFloat("translationX", 0f, trans));

        ValueAnimator translateY = ObjectAnimator.ofPropertyValuesHolder(
                itemView, PropertyValuesHolder.ofFloat("translationY", 0f, DisplayUtil.dip2px(GlobalContext.getAppContext(), 265 * 0.2f)));

        translateX.setDuration(500);
        translateY.setDuration(500);
        cardAnimationSet = new AnimatorSet();
        cardAnimationSet.setInterpolator(new AccelerateInterpolator());
        cardAnimationSet.playTogether(rotation, translateX, translateY);
        cardAnimationSet.start();
        ObjectAnimator overlayAnimator = ObjectAnimator.ofFloat(like, "alpha", 0f, 1f);
        overlayAnimator.setDuration(300);

        likeActionAnimationSet = new AnimatorSet();
        likeActionAnimationSet.playTogether(overlayAnimator);
        likeActionAnimationSet.start();
        cardAnimationSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (position < mItems.size()) {
                    mItems.remove(position);
                    notifyItemRemoved(position);
                    if (mExecuteListener != null) {
                        mExecuteListener.onLikeAnimExecuteListener(LikeExecuteListener.END);
                        mExecuteListener.onLikeActionCallback(position, detailEntity, MatchPairConstant.LIKE_ACTION);
                    }
                } else {
                    notifyDataSetChanged();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        schedule = AndroidSchedulers.mainThread().createWorker()
                .schedule(new Action0() {
                    @Override
                    public void call() {
                        itemView.setRotation(0);
                        itemView.setTranslationX(0);
                        itemView.setTranslationY(0);
                        like.setAlpha(0f);
                    }
                }, 800, TimeUnit.MILLISECONDS);
    }

完整代码

完整代码掺杂了很多业务逻辑,但不影响同学们理解。看大题的用法即可

LikeMeActivity

public class LikeMeActivity extends BaseActivity implements View.OnClickListener {
    private TextView like_me_num;
    private RecyclerView like_me_list;
    private View empty_view;

    private CompositeSubscription mSubscription = new CompositeSubscription();
    private RecyclerGridSlipAdapter adapter;
    private List<LikeMeDetailEntity> likeMes;
    private SwipeRefreshLayout swipe_refresh;
    private LikeMeItemTouchHelperCallback callback;
    private LikeMeModel mLikeMeModel = new LikeMeModel();

    //是不是最后一页
    private boolean is_last_page = false;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.like_me_layout);
        like_me_num = findViewById(R.id.like_me_num);
        like_me_list = findViewById(R.id.like_me_list);
        swipe_refresh = findViewById(R.id.swipe_refresh);
        empty_view = findViewById(R.id.empty_view);
        findViewById(R.id.like_me_title).setOnClickListener(this);
        findViewById(R.id.page_back).setOnClickListener(this);

        adapter = new RecyclerGridSlipAdapter();

        like_me_list.setHasFixedSize(true);
        like_me_list.setAdapter(adapter);
        like_me_list.setLayoutManager(new GridLayoutManager(this, 2));

        callback = new LikeMeItemTouchHelperCallback(adapter);
        ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(like_me_list);
        adapter.setExecuteListener(new RecyclerGridSlipAdapter.LikeExecuteListener() {
            @Override
            public void onLikeAnimExecuteListener(int status) {
                switch (status) {
                    case RecyclerGridSlipAdapter.LikeExecuteListener.START:
                        callback.setCanSwipe(false);
                        break;
                    case RecyclerGridSlipAdapter.LikeExecuteListener.END:
                        callback.setCanSwipe(true);
                        break;
                }
            }

            @Override
            public void onLikeActionCallback(int position, LikeMeDetailEntity likeDetail, String action) {
                likeAction(position, likeDetail, action);
            }
        });
        loadData(0);

        like_me_list.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                if (recyclerView.getLayoutManager() == null) {
                    return;
                }
                //当前RecyclerView显示出来的最后一个的item的position
                int lastPosition = -1;

                //当前状态为停止滑动状态SCROLL_STATE_IDLE时
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                    if (layoutManager instanceof GridLayoutManager) {
                        //通过LayoutManager找到当前显示的最后的item的position
                        lastPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
                    }

                    //时判断界面显示的最后item的position是否等于itemCount总数-1也就是最后一个item的position
                    //如果相等则说明已经滑动到最后了
                    if (lastPosition == recyclerView.getLayoutManager().getItemCount() - 1) {
                        loadData(likeMes != null && !likeMes.isEmpty() ? likeMes.get(likeMes.size() - 1).beliked_timestamp : 0);
                    }

                }
            }
        });

        swipe_refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                loadData(0);
                final Subscription schedule = AndroidSchedulers.mainThread()
                        .createWorker()
                        .schedule(new Action0() {
                            @Override
                            public void call() {
                                swipe_refresh.setRefreshing(false);
                            }
                        }, 300, TimeUnit.MILLISECONDS);
                mSubscription.add(schedule);
            }
        });
    }


    private void loadData(final long last_timestamp) {
        if (is_last_page && last_timestamp != 0) {
            return;
        }
        final Subscription subscribe = MatchPairNetManager.getLikeMeList(last_timestamp)
                .doOnNext(new Action1<RspQueenDefault<LikeMeResult>>() {
                    @Override
                    public void call(RspQueenDefault<LikeMeResult> rsp) {
                        swipe_refresh.setRefreshing(false);
                        if (rsp.isSuccess() && rsp.getResultEntity() != null && rsp.getResultEntity().data != null) {
                            if (last_timestamp == 0) {
                                if (rsp.getResultEntity().data.items == null || rsp.getResultEntity().data.items.isEmpty()) {
                                    empty_view.setVisibility(View.VISIBLE);
                                } else {
                                    empty_view.setVisibility(View.GONE);
                                }
                            } else {
                                empty_view.setVisibility(View.GONE);
                            }
                            callback.setLike_num(rsp.getResultEntity().data.left_like_count);
                            adapter.setLike_num(rsp.getResultEntity().data.left_like_count);
                            final LikeMeInfoEntity data = rsp.getResultEntity().data;
                            like_me_num.setText(String.valueOf(data.beliked_num));
                            if (last_timestamp != 0) {
                                mergeListView(data.items);
                            } else {
                                likeMes = rsp.getResultEntity().data.items;
                            }
                            adapter.refreshAllDate(likeMes);

                            is_last_page = rsp.getResultEntity().data.is_last_page == 1;
                        } else {
                            if (last_timestamp == 0) {
                                empty_view.setVisibility(View.VISIBLE);
                            }
                        }
                    }
                })
                .subscribe(new DefaultSubscriber<>("refreshData"));
        mSubscription.add(subscribe);
    }


    private void likeAction(final int position, final LikeMeDetailEntity likeDetail, final String action) {
        final Subscription subscribe = mLikeMeModel.beLikeAction(likeDetail.info.uid, action)
                .doOnNext(new Action1<RspQueenDefault<LikeMeActionResult>>() {
                    @Override
                    public void call(RspQueenDefault<LikeMeActionResult> rsp) {
                        if (!rsp.isSuccess) {
                            ToastUtils.showToast(rsp.getErrorMessage());
                            //adapter.insertDate(position, likeDetail);
                        }
                        if (rsp.isSuccess && rsp.getResultEntity() != null && rsp.getResultEntity().data != null) {
                            callback.setLike_num(rsp.getResultEntity().data.left_like_count);
                            adapter.setLike_num(rsp.getResultEntity().data.left_like_count);
                            if (TextUtils.equals(action, MatchPairConstant.LIKE_ACTION)) {
                                final AppInNotifyManager notifyManager = new AppInNotifyManager();
                                notifyManager.setActivity(LikeMeActivity.this);
                                notifyManager.showInnerNotifyView(new AppInnerEntity(likeDetail.info), AppInnerNotifyView.NOTIFY_LIKE_ME, new AppInnerNotifyView.InnerNotifyClickListener() {
                                    @Override
                                    public void onInnerNotifyClickListener() {
                                        ChatUiManager.startMessagePage(LikeMeActivity.this, likeDetail.info.uid, QueenChatConstant.FROM_NOTIFY);
                                    }
                                });
                            }
                            removeItem(likeDetail.info.uid);
                            if (likeMes == null || likeMes.isEmpty()) {
                                empty_view.setVisibility(View.VISIBLE);
                            } else {
                                empty_view.setVisibility(View.GONE);
                            }
                        }
                    }
                })
                .subscribe(new DefaultSubscriber<>("likeAction"));
        mSubscription.add(subscribe);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSubscription.clear();
        if (adapter != null) {
            adapter.release();
        }

        EventBus.getDefault().unregister(this);
    }

    @Subscribe
    public void onEventMainThread(BeLikeLikeSuccessEvent event) {
        //收到喜欢的通知,需要将此人移除
        if (event != null) {
            final int uid = event.uid;
            removeItem(uid);
            if (likeMes == null || likeMes.isEmpty()) {
                empty_view.setVisibility(View.VISIBLE);
            } else {
                empty_view.setVisibility(View.GONE);
            }
        }
    }

    private void removeItem(int uid) {
        for (int i = 0; likeMes != null && i < likeMes.size(); i++) {
            if (likeMes.get(i) != null &&
                    likeMes.get(i).info != null &&
                    likeMes.get(i).info.uid == uid) {
                likeMes.remove(i);
                if (adapter != null) {
                    adapter.refreshAllDate(likeMes);
                }
                break;
            }
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.page_back:
                finish();
                break;
        }
    }

    private static final String TAG = "LikeMeActivity";

    private void mergeListView(List<LikeMeDetailEntity> likeMesNow) {
        if (likeMes == null || likeMes.isEmpty()) {
            likeMes = likeMesNow;
            return;
        }

        if (likeMesNow != null && !likeMesNow.isEmpty()) {
            Iterator iterator = likeMesNow.iterator();
            while (iterator.hasNext()) {
                final LikeMeDetailEntity next = (LikeMeDetailEntity) iterator.next();
                if (likeMes.contains(next)) {
                    iterator.remove();
                }
            }
            likeMes.addAll(likeMesNow);
        }
    }
}

LikeMeItemTouchHelperCallback

/**
 * 谁喜欢我订制
 */
public class LikeMeItemTouchHelperCallback extends ItemTouchHelper.Callback {
    private static final String TAG = "SlipItemTouchHelperCall";

    private String swipeAction = "";

    public static final float ALPHA_FULL = 1.0f;

    private final ItemTouchHelperAdapter mAdapter;
    private boolean isCanSwipe = true;

    private int like_num;

    public void setLike_num(int like_num) {
        this.like_num = like_num;
    }

    public LikeMeItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        mAdapter = adapter;
    }

    public void setCanSwipe(boolean canSwipe) {
        isCanSwipe = canSwipe;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return false;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return isCanSwipe;
    }

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        // Set movement flags based on the layout manager
        final int dragFlags = 0;
        final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, @NonNull 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(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
        // Notify the adapter of the dismissal
        if (like_num <= 0 && TextUtils.equals(swipeAction, MatchPairConstant.LIKE_ACTION)) {
            //如果剩余喜欢次数小于零,并且是喜欢,则反馈
            mAdapter.onItemReset(viewHolder, viewHolder.getAdapterPosition());
        } else {
            mAdapter.onItemDismiss(swipeAction, viewHolder.getAdapterPosition());
        }
        swipeAction = "";

    }

    //滑动到删除的速度
    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return super.getSwipeEscapeVelocity(defaultValue);
    }

    @Override
    public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
        return 400;
        //return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
    }

    //滑动到删除的距离
    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        //return super.getSwipeThreshold(viewHolder);
        return 0.30f;
    }


    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {

            //为了把view提到顶部
            takeViewTopInRec(recyclerView, viewHolder, isCurrentlyActive);

            final int width = viewHolder.itemView.getWidth();
            final int height = viewHolder.itemView.getHeight();
            // Fade out the view as it is swiped out of the parent's bounds
            final float r = Math.abs(dX) / (float) width;

            final float alpha = ALPHA_FULL - r;

            viewHolder.itemView.setTranslationX(dX * 1.1f);

            if (r < 0.3) {
                viewHolder.itemView.setScaleX(1 + r * 0.2f);
                viewHolder.itemView.setScaleY(1 + r * 0.2f);
            }

            viewHolder.itemView.setTranslationY(r * height * 0.2f);
            if (dX >= 0) {
                swipeAction = MatchPairConstant.LIKE_ACTION;
                viewHolder.itemView.setRotation(10 * r);
                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).like.setAlpha(r * 4f > 1 ? 1f : r * 4f);
                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).dislike.setAlpha(0f);

            } else {
                swipeAction = MatchPairConstant.DIS_LIKE_ACTION;
                viewHolder.itemView.setRotation(-10 * r);

                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).dislike.setAlpha(r * 4f > 1 ? 1f : r * 4f);
                ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).like.setAlpha(0f);
            }
            /*if (r > 0.5) {
                viewHolder.itemView.setAlpha(alpha * 2f);
            }*/

        } 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 ItemTouchHelperViewHolder) {
                // Let the view holder know that this item is being moved or dragged
                ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
                itemViewHolder.onItemSelected();
            }
        }

        super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setAlpha(ALPHA_FULL);
        viewHolder.itemView.setRotation(0);
        viewHolder.itemView.setTranslationX(0);
        viewHolder.itemView.setTranslationY(0);
        viewHolder.itemView.setScaleX(1);
        viewHolder.itemView.setScaleY(1);
        ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).like.setAlpha(0f);
        ((RecyclerGridSlipAdapter.ItemViewHolder) viewHolder).dislike.setAlpha(0f);
        // Tell the view holder it's time to restore the idle state
        ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
        itemViewHolder.onItemClear();
    }

    public static void takeViewTopInRec(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, boolean isCurrentlyActive) {
        if (Build.VERSION.SDK_INT >= 21 && isCurrentlyActive) {
            Object originalElevation = viewHolder.itemView.getTag(android.support.v7.recyclerview.R.id.item_touch_helper_previous_elevation);
            if (originalElevation == null) {
                originalElevation = ViewCompat.getElevation(viewHolder.itemView);
                float newElevation = 1.0F + findMaxElevation(recyclerView, viewHolder.itemView);
                ViewCompat.setElevation(viewHolder.itemView, newElevation);
                viewHolder.itemView.setTag(android.support.v7.recyclerview.R.id.item_touch_helper_previous_elevation, originalElevation);
            }
        }
    }

    private static float findMaxElevation(RecyclerView recyclerView, View itemView) {
        int childCount = recyclerView.getChildCount();
        float max = 0.0F;

        for (int i = 0; i < childCount; ++i) {
            View child = recyclerView.getChildAt(i);
            if (child != itemView) {
                float elevation = ViewCompat.getElevation(child);
                if (elevation > max) {
                    max = elevation;
                }
            }
        }

        return max;
    }

}

RecyclerGridSlipAdapter

public class RecyclerGridSlipAdapter extends RecyclerView.Adapter<RecyclerGridSlipAdapter.ItemViewHolder>
        implements ItemTouchHelperAdapter {

    private final List<LikeMeDetailEntity> mItems = new ArrayList<>();

    private RecyclerView recyclerView;
    private Subscription schedule;
    private AnimatorSet likeActionAnimationSet;
    private AnimatorSet cardAnimationSet;

    private int like_num;

    public RecyclerGridSlipAdapter() {
    }

    public void setLike_num(int like_num) {
        this.like_num = like_num;
    }

    public void refreshAllDate(List<LikeMeDetailEntity> dates) {
        if (dates != null) {
            mItems.clear();
            mItems.addAll(dates);
            notifyDataSetChanged();
        }
    }

    public void insertDate(int position, LikeMeDetailEntity meDetail) {
        if (position <= mItems.size() && meDetail != null) {
            mItems.add(position, meDetail);
            notifyItemInserted(position);
        }
    }

    @Override
    @NonNull
    public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_like_me, parent, false);
        return new ItemViewHolder(view);
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(@NonNull final ItemViewHolder holder, int position) {
        final int adapterPosition = holder.getAdapterPosition();
        final LikeMeDetailEntity detailEntity = mItems.get(adapterPosition);
        if (detailEntity != null) {
            if (detailEntity.info != null && !TextUtils.isEmpty(detailEntity.info.nick)) {
                holder.name.setText(detailEntity.info.nick);
                holder.age.setText("," + detailEntity.info.age);
            }
            if (!TextUtils.isEmpty(detailEntity.distance)) {
                holder.distance.setText(detailEntity.distance);
            }
            if (detailEntity.info != null) {
                LoadPicUtils.loadHalfPic(detailEntity.info.portrait, holder.avatar);
            }
        }

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ClickUtils.isCommonClick(v) && detailEntity != null && detailEntity.info != null) {
                    ProfileUiManager.openHomePageActivity(v.getContext(), detailEntity.info.uid, HomePageActivity.BE_LIKE_ME,5);
                }
            }
        });


        holder.to_like.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ClickUtils.isCommonClick(v)) {
                    if (like_num <= 0) {
                        ToastUtils.showToast(GlobalContext.getString(R.string.no_like_me_like_time));
                        return;
                    }
                    swipeRight(detailEntity, holder, adapterPosition);
                }
            }
        });
    }

    @Override
    public void onItemDismiss(String action, int position) {
        final LikeMeDetailEntity likeMeDetailEntity = mItems.get(position);
        mItems.remove(position);
        notifyItemRemoved(position);
        if (mExecuteListener != null) {
            mExecuteListener.onLikeActionCallback(position, likeMeDetailEntity, action);
        }
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        Collections.swap(mItems, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    @Override
    public void onItemReset(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
        //notifyDataSetChanged();
        ToastUtils.showToast(GlobalContext.getString(R.string.no_like_me_like_time));
        notifyItemChanged(position);
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        this.recyclerView = recyclerView;
        super.onAttachedToRecyclerView(recyclerView);
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    private static final String TAG = "RecyclerGridSlipAdapter";

    /**
     * Simple example of a view holder that implements {@link ItemTouchHelperViewHolder} and has a
     * "handle" view that initiates a drag event when touched.
     */
    public static class ItemViewHolder extends RecyclerView.ViewHolder implements
            ItemTouchHelperViewHolder {
        public SimpleDraweeView avatar;
        public ImageView like;
        public ImageView dislike;
        public ImageView to_like;
        public TextView name;
        public TextView age;
        public TextView distance;

        ItemViewHolder(View itemView) {
            super(itemView);
            like = itemView.findViewById(R.id.like);
            like.setAlpha(0f);

            dislike = itemView.findViewById(R.id.dislike);
            dislike.setAlpha(0f);
            to_like = itemView.findViewById(R.id.to_like);
            distance = itemView.findViewById(R.id.distance);
            name = itemView.findViewById(R.id.name);
            age = itemView.findViewById(R.id.age);
            avatar = itemView.findViewById(R.id.avatar);
        }

        @Override
        public void onItemSelected() {
            Log.i(TAG, "onItemSelected: ");
        }

        @Override
        public void onItemClear() {
        }
    }

    private LikeExecuteListener mExecuteListener;

    public void setExecuteListener(LikeExecuteListener executeListener) {
        mExecuteListener = executeListener;
    }

    private void swipeRight(final LikeMeDetailEntity detailEntity, ItemViewHolder holder, final int position) {
        clearAnim();
        final int widthPixels = GlobalContext.getDisplayMetrics().widthPixels;
        if (mExecuteListener != null) {
            mExecuteListener.onLikeAnimExecuteListener(LikeExecuteListener.START);
        }
        LikeMeItemTouchHelperCallback.takeViewTopInRec(recyclerView, holder, true);

        final View itemView = holder.itemView;
        final View like = holder.like;
        ValueAnimator rotation = ObjectAnimator.ofPropertyValuesHolder(
                itemView, PropertyValuesHolder.ofFloat("rotation", 30f));
        rotation.setDuration(300);
        float trans = itemView.getWidth() + widthPixels;
        ValueAnimator translateX = ObjectAnimator.ofPropertyValuesHolder(
                itemView, PropertyValuesHolder.ofFloat("translationX", 0f, trans));

        ValueAnimator translateY = ObjectAnimator.ofPropertyValuesHolder(
                itemView, PropertyValuesHolder.ofFloat("translationY", 0f, DisplayUtil.dip2px(GlobalContext.getAppContext(), 265 * 0.2f)));

        translateX.setDuration(500);
        translateY.setDuration(500);
        cardAnimationSet = new AnimatorSet();
        cardAnimationSet.setInterpolator(new AccelerateInterpolator());
        cardAnimationSet.playTogether(rotation, translateX, translateY);
        cardAnimationSet.start();
        ObjectAnimator overlayAnimator = ObjectAnimator.ofFloat(like, "alpha", 0f, 1f);
        overlayAnimator.setDuration(300);

        likeActionAnimationSet = new AnimatorSet();
        likeActionAnimationSet.playTogether(overlayAnimator);
        likeActionAnimationSet.start();
        cardAnimationSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (position < mItems.size()) {
                    mItems.remove(position);
                    notifyItemRemoved(position);
                    if (mExecuteListener != null) {
                        mExecuteListener.onLikeAnimExecuteListener(LikeExecuteListener.END);
                        mExecuteListener.onLikeActionCallback(position, detailEntity, MatchPairConstant.LIKE_ACTION);
                    }
                } else {
                    notifyDataSetChanged();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        schedule = AndroidSchedulers.mainThread().createWorker()
                .schedule(new Action0() {
                    @Override
                    public void call() {
                        itemView.setRotation(0);
                        itemView.setTranslationX(0);
                        itemView.setTranslationY(0);
                        like.setAlpha(0f);
                    }
                }, 800, TimeUnit.MILLISECONDS);
    }

    public void release() {
        if (schedule != null) {
            schedule.unsubscribe();
        }
        clearAnim();
    }

    private void clearAnim() {
        if (cardAnimationSet != null) {
            cardAnimationSet.cancel();
        }

        if (likeActionAnimationSet != null) {
            likeActionAnimationSet.cancel();
        }
    }

    public interface LikeExecuteListener {
        int START = 0;
        int END = 2;

        void onLikeAnimExecuteListener(int status);

        void onLikeActionCallback(int position, LikeMeDetailEntity likeDetail, String action);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容