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移除后重置等)通知業(yè)務層

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

完整代碼

完整代碼摻雜了很多業(yè)務邏輯吆寨,但不影響同學們理解赏淌。看大題的用法即可

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;

                //當前狀態(tài)為停止滑動狀態(tài)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閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異博脑,居然都是意外死亡憎乙,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門叉趣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泞边,“玉大人,你說我怎么就攤上這事疗杉≌笱瑁” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵烟具,是天一觀的道長梢什。 經常有香客問我,道長朝聋,這世上最難降的妖魔是什么嗡午? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮冀痕,結果婚禮上荔睹,老公的妹妹穿的比我還像新娘。我一直安慰自己言蛇,他們只是感情好僻他,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腊尚,像睡著了一般中姜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跟伏,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天丢胚,我揣著相機與錄音,去河邊找鬼受扳。 笑死携龟,一個胖子當著我的面吹牛,可吹牛的內容都是我干的勘高。 我是一名探鬼主播峡蟋,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼坟桅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蕊蝗?” 一聲冷哼從身側響起仅乓,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蓬戚,沒想到半個月后夸楣,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡子漩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年豫喧,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幢泼。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡紧显,死狀恐怖,靈堂內的尸體忽然破棺而出缕棵,到底是詐尸還是另有隱情孵班,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布招驴,位于F島的核電站篙程,受9級特大地震影響,放射性物質發(fā)生泄漏忽匈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一矿辽、第九天 我趴在偏房一處隱蔽的房頂上張望丹允。 院中可真熱鬧,春花似錦袋倔、人聲如沸雕蔽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽批狐。三九已至,卻和暖如春前塔,著一層夾襖步出監(jiān)牢的瞬間嚣艇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工华弓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留食零,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓寂屏,卻偏偏與公主長得像贰谣,于是被迫代替她去往敵國和親娜搂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容