Android学习笔记030之RecyclerView和CardView实现拖拽和滑动

Android学习笔记030之RecyclerView和CardView实现拖拽和滑动

  在上一篇中,我们介绍了SwiperefreshLayout、RecyclerView和CardView,还用着三个控件组合实现了一些效果,下拉刷新也不在需要用第三方的框架,实现的效果也比较符合Google的MD设计,这一节,我们使用RecyclerView和CardView组合实现拖拽和滑动删除的效果。

RecyclerView实现拖拽和滑动删除非常简单,只需要实现下面的三句代码:

     //关联RecyclerView
    ItemTouchHelper.Callback callback=new ItemTouchCallback(dragAdapter);
    ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);
    itemTouchHelper.attachToRecyclerView(rv_drag_list);

  我们看到,要实现拖拽和滑动删除需要实现一个适配器和一个回调接口。其中,这个回调接口需要我们自己去实现,重点就是实现的这个回调接口,下面我们具体介绍一下这个自定义的回调接口:

我们自定义一个类,实现ItemTouchHelper.Callback这个接口,先看一下具体的自定义回调接口的源码

package com.example.newapidemo.common;

import android.graphics.Canvas;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

/**
 * Created by Devin on 2016/7/15.
 */
public class ItemTouchCallback extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private ItemTouchAdapter itemTouchAdapter;

public ItemTouchCallback(ItemTouchAdapter itemTouchAdapter) {
    this.itemTouchAdapter = itemTouchAdapter;
}

/**
 * 指定可以支持的拖放和滑动的方向
 * List类型的RecyclerView,拖拽只有UP、DOWN
 * Grid类型的则有UP、DOWN、LEFT、RIGHT四个方向
 * <p/>
 * dragFlags 是拖拽标志,swipeFlags是滑动标志,在Grid中把swipeFlags设置为0,表示不处理滑动操作。
 *
 * @param recyclerView
 * @param viewHolder
 * @return
 */
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    //判断recyclerView传入的LayoutManager是不是GridLayoutManager
    if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
        //Grid的拖拽方向,上、下、左、右
        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        //设置为0,表示不支持滑动
        final int swipeFlags = 0;
        //创建拖拽或者滑动标志的快速方式
        return makeMovementFlags(dragFlags, swipeFlags);
    } else {
        //List类型的拖拽方向,上或者下
        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        //List类型支持滑动,左或者右
        final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        //创建拖拽或者滑动标志的快速方式
        return makeMovementFlags(dragFlags, swipeFlags);
    }
}

/**
 * 告诉ItemTouchHelper是否需要RecyclerView支持长按拖拽,返回true是支持,false是不支持
 *
 * @return
 */
@Override
public boolean isLongPressDragEnabled() {
    return true;
}

/**
 * 告诉ItemTouchHelper是否需要RecyclerView支持滑动,返回true是支持,false是不支持
 *
 * @return
 */
@Override
public boolean isItemViewSwipeEnabled() {
    return true;
}

/**
 * 当拖拽开始的时候调用
 *
 * @param viewHolder
 * @param actionState
 */
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
    //拖拽的时候改变一下选中Item的颜色
    if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
        if (viewHolder instanceof ItemTouchHelperViewHolder) {
            //让ViewHolder知道Item开始选中
            ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
            //回调ItemTouchHelperVIewHolder的方法
            itemViewHolder.onItemSelected();
        }
    }
    super.onSelectedChanged(viewHolder, actionState);
}

/**
 * 当拖拽结束的时候调用
 *
 * @param recyclerView
 * @param viewHolder
 */
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    super.clearView(recyclerView, viewHolder);
    viewHolder.itemView.setAlpha(ALPHA_FULL);
    if (viewHolder instanceof ItemTouchHelperViewHolder) {
        ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
        //Item移动完成之后的回调
        itemViewHolder.onItemClear();
    }
}

/**
 * 当ItemTouchHelper要拖动的Item从原来位置拖动到新的位置的时候调用
 * 当我们拖拽的时候调用这个方法
 *
 * @param recyclerView
 * @param viewHolder
 * @param target
 * @return
 */
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    //如果两个item不是一个类型的,我们让他不可以拖拽
    if (viewHolder.getItemViewType() != target.getItemViewType()) {
        return false;
    }

    //得到拖动ViewHolder的position
    int fromPosition = viewHolder.getAdapterPosition();
    //得到目标ViewHolder的position
    int toPosition = target.getAdapterPosition();
    itemTouchAdapter.onItemMove(fromPosition, toPosition);

    return true;
}

/**
 * 当ViewHolder滑动的时候调用
 * 当滑动Item的时候调用此方法
 *
 * @param viewHolder
 * @param direction
 */
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    itemTouchAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}

/**
 * 由 ItemTouchHelper 在 RecyclerView 的 onDraw方法中回调调用
 *
 * @param c
 * @param recyclerView
 * @param viewHolder
 * @param dX
 * @param dY
 * @param actionState
 * @param isCurrentlyActive
 */
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
        final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
        viewHolder.itemView.setAlpha(alpha);
        viewHolder.itemView.setTranslationX(dX);
    } else {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }
}
}

除了这个回调接口之外,我们还定义了几个接口

package com.example.newapidemo.common;
/**
 * Created by Devin on 2016/7/15.
 */
public interface ItemTouchHelperViewHolder {
/**
 * 当Item开始拖拽或者滑动的时候调用
 */
void onItemSelected();

/**
 * 当Item完成拖拽或者滑动的时候调用
 */
void onItemClear();
}

这个接口是实现拖拽或者滑动完成或者正在拖拽或滑动的回调,我们可以定义拖拽或者滑动时候一些样式或者其他想要实现的效果。

还有一个就是适配器需要实现的接口:

package com.example.newapidemo.common;

/**
 * Created by Devin on 2016/7/15.
 */
public interface ItemTouchAdapter {
/**
 * Item已经移动的足够远的时候调用
 *
 * @param fromPosition
 * @param toPosition
 * @return
 */
boolean onItemMove(int fromPosition, int toPosition);

/**
 * 当Item滑动取消的时候调用
 *
 * @param position
 */
void onItemDismiss(int position);
}

这个接口就不在描述很多了。

在我们实现那个回调接口的时候,就有做判断,当RecyclerView时List列表样式的时候就可以实现滑动删除和拖拽两种效果,但是是Grid网格效果的时候就只能拖拽。下面我们看一下适配器的实现:

package com.example.newapidemo.adapter;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.newapidemo.R;
import com.example.newapidemo.common.ItemTouchAdapter;
import com.example.newapidemo.common.ItemTouchHelperViewHolder;
import com.example.newapidemo.domain.RVTest;

import java.util.Collections;
import java.util.List;

/**
 * Created by Devin on 2016/7/18.
 */
public class RVDragAdapter extends RecyclerView.Adapter<RVDragAdapter.RVDragViewHolder> implements ItemTouchAdapter {
private Context mContext;
private List<RVTest> datas;

public RVDragAdapter(Context mContext, List<RVTest> datas) {
    this.mContext = mContext;
    this.datas = datas;
}

@Override
public RVDragViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.item_fragment_list, parent, false);
    return new RVDragViewHolder(view);
}

@Override
public void onBindViewHolder(RVDragViewHolder holder, int position) {
    holder.tv_drag_list.setText(datas.get(position).getContent());
}

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

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

@Override
public void onItemDismiss(int position) {
    datas.remove(position);
    notifyItemRemoved(position);
}

public static class RVDragViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {
    TextView tv_drag_list;
    CardView cv_drag;

    public RVDragViewHolder(View itemView) {
        super(itemView);
        tv_drag_list
                = (TextView) itemView.findViewById(R.id.tv_drag_list);
        cv_drag = (CardView) itemView.findViewById(R.id.cv_drag);
    }

    //设置item选中拖拽的时候调用
    @Override
    public void onItemSelected() {
        itemView.setBackgroundColor(Color.GRAY);
        cv_drag.setRadius(R.dimen.cv_drag);
    }

    //当Item拖拽完成时候调用
    @Override
    public void onItemClear() {
        itemView.setBackgroundColor(Color.WHITE);
        cv_drag.setRadius(R.dimen.cv_drag);
    }
}
}

适配器的实现跟其他实现RecyclerView的适配器差不多,但是必须要实现ItemTouchAdapter这个接口,ViewHolder也需要实现ItemTouchHelperViewHolder这个接口,这是我们自定义的接口,里面提供我们的几个回调,可以更改一些设置,在这里就简单的实现拖拽之后Item的一些简单样式。

最后是Fragment的实现:

 @Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rvlist, container, false);
    rv_drag_list = (RecyclerView) view.findViewById(R.id.rv_drag_list);
    initData();
    rv_drag_list.setLayoutManager(new LinearLayoutManager(getContext()));
    dragAdapter = new RVDragAdapter(getContext(), datas);
    rv_drag_list.setAdapter(dragAdapter);
    //关联RecyclerView
    ItemTouchHelper.Callback callback=new ItemTouchCallback(dragAdapter);
    ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);
    itemTouchHelper.attachToRecyclerView(rv_drag_list);
    return view;
}

private void initData() {
    if (datas == null) {
        datas = new ArrayList<>();
    }
    for (int i = 0; i < 20; i++) {
        datas.add(new RVTest(i, "测试数据第 " + (i + 1) + " 条"));
    }

}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rvgrid, container, false);
    rv_drag_grid = (RecyclerView) view.findViewById(R.id.rv_drag_grid);
    rv_drag_grid.setLayoutManager(new GridLayoutManager(getContext(), 2));
    initData();
    adapter=new RVDragAdapter(getContext(),datas);
    rv_drag_grid.setAdapter(adapter);
    ItemTouchCallback callback=new ItemTouchCallback(adapter);
    ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback);
    itemTouchHelper.attachToRecyclerView(rv_drag_grid);
    return view;
}
private void initData() {
    if (datas == null) {
        datas = new ArrayList<>();
    }
    for (int i = 0; i < 40; i++) {
        datas.add(new RVTest(i, "第 " + (i + 1) + " 条数据"));
    }

}

这里都是很简单的实现,下面我们看一下效果图:

这只是很简单的实现,在实际项目中可以按自己的需求做扩展。下面是Demo的源码

猛戳下载Demo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值