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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RecyclerViewCardViewAndroid 开发中常用的两个控件,它们经常被一起使用来实现列表展示的功能。 RecyclerViewAndroid 自带的列表控件,相比于 ListView 和 GridView,它具有更好的性能和更加灵活的布局方式。相比于 ListViewRecyclerView 可以实现更好的复用机制,可以提高列表的滑动流畅度和减少内存占用。 CardViewAndroid 自带的卡片式布局控件,它可以让布局具有卡片的效果,常用于展示某个条目的详细信息。CardView 可以嵌套在 RecyclerView 中使用,实现列表中每个条目都是卡片的效果,同时也可以添加点击事件和动画效果。 在使用 RecyclerViewCardView 实现列表展示的时候,我们需要先创建一个 RecyclerView,并设置相应的布局管理器和适配器。适配器需要继承 RecyclerView.Adapter 类,实现相应的方法,以便于渲染每个条目的数据。在适配器中,我们可以创建一个 ViewHolder,用来缓存每个条目的 View。 然后,我们需要创建一个 CardView,用来展示每个条目的数据。在 CardView 中,我们可以添加图片、文字、按钮等控件,来展示每个条目的详细信息。同时,我们也可以给 CardView 设置点击事件,以便于用户点击后跳转到相应的界面。 最后,我们需要将适配器设置到 RecyclerView 中,让 RecyclerView 显示我们的列表。在适配器中,我们还可以添加一些动画效果,让列表更加生动有趣。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值