Android 初步实现item可拖拽RecyclerView (Grid模式下)
0.首先先给一张效果图。部分功能么有实现,好吧我承认我不太会。仅仅给自己留个记录。供参考。
1.先说下思路 用到的类:DragParent (继承RelativeLayout) 、DragGridView (继承RecyclerView)、Bean item数据项、DragAdapter (DragGridView适配器)
外加2个接口PreDragListener(即将进入拖拽状态)、DraggingListener(拖拽中,拖拽结束)。
2.当长按 DragGridView 的item时,该Item View设置不可见状态,通过接口方法告知 DragParent 即将进入拖拽状态。
3.DragParent 进入拖拽状态 马上获取被拖拽item View 对应的Bitmap,并把该Bitmap放入ImageView中,添加到DragParent 内部 item view的位置。
4.重写DragParent dispatchTouchEvent() ,在拖拽状态下 Move 计算当前event x、y坐标位于DragGridView 的那个位置。
5.如果被拖拽的item的位置与当前拖拽点x、y坐标所属item位置不一致,说明需要DragGridView remove掉被拖拽item ,并且在当前拖拽点位置insert。
6.首先自定义一个ID。遇到不要忘记,主要是实现 DragGridView 的itemView与 Bean进行绑定用的。
7.先看看 Bean 和接口类 简写了。
public class Bean {
String str;//item+i
boolean isDragged;//是否处于拖拽状态
int rid;//该Bean对应的 图片资源id
boolean isLongClicked;
public Bean(String str, int rid) {
this.str = str;
this.rid = rid;
}
}
public interface PreDragListener {
/**
* 某个DragGridView 的ItemView 进入拖拽状态回调
*/
void preDrag(View view);
}
public interface DraggingListener {
/**
* 拖拽中时,返回的当前拖拽的坐标
*/
void dragging(float x, float y);
void dragEnd();
}
9.DragGridView 实现了DraggingListener,当DragParent 内部添加的imageview移动时,不断检测拖拽点在DragGridView 的位置并做remove和insert。
10.先看下DragAdapter ,内部调用PreDragListener。
public class DragAdapter extends RecyclerView.Adapter implements View.OnLongClickListener, View.OnClickListener {
Context mContext;
public List mBeans = new ArrayList<>();
PreDragListener mListener;
public Bean draggedBean;
public void setListener(PreDragListener listener) {
mListener = listener;
}
public DragAdapter(Context context) {
mContext = context;
int[] rids = new int[]{R.mipmap.a1, R.mipmap.a2, R.mipmap.a3, R.mipmap.a4, R.mipmap.a5, R.mipmap.a6
, R.mipmap.a7, R.mipmap.a8, R.mipmap.a9, R.mipmap.a10, R.mipmap.a11, R.mipmap.a12};
for (int i = 0; i < 12; i++) {
mBeans.add(new Bean("item+" + i, rids[i % rids.length]));
}
}
@Override
public ViewH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false);
ViewH tag = new ViewH(view);
view.setTag(tag);
return tag;
}
@Override
public void onBindViewHolder(ViewH holder, int position) {
Bean bean = mBeans.get(position);
if (bean.isLongClicked()) {
holder.icon.setVisibility(View.VISIBLE);
} else {
holder.icon.setVisibility(View.GONE);
}
if (bean.isDragged()) {
holder.itemView.setVisibility(View.INVISIBLE);
} else {
holder.itemView.setVisibility(View.VISIBLE);
}
holder.img.setImageResource(bean.getRid());
holder.tv.setText(bean.getStr());
//***需要每个显示的itemView 与其所显示的数据Bean进行绑定
holder.itemView.setTag(R.id.id_bean_, mBeans.get(position));
holder.itemView.setOnLongClickListener(this);//长按
holder.itemView.setOnClickListener(this);//短按
}
@Override
public int getItemCount() {
return mBeans.size();
}
@Override
public boolean onLongClick(View v) {
//**长按时 获取该itemView 所绑定的Bean
draggedBean = (Bean) v.getTag(R.id.id_bean_);
draggedBean.setIsDragged(true);
//**通知 该Bean所在mBeans位置发生变化
notifyItemChanged(mBeans.indexOf(draggedBean));
//**回调 DragParent 对DragGridView事件进行拦截
if (mListener != null) {
mListener.preDrag(v);
}
return true;
}
/**
* 对外提供 拖拽结束时方法,对应呗拖拽数据重置拖拽状态 并刷新
*/
public void dragEnd() {
int index = mBeans.indexOf(draggedBean);
draggedBean.setIsDragged(false);
notifyItemChanged(index);
draggedBean = null;
}
/**
* 对外方法 获取当前拖拽Bean位于 mBeans的位置
*/
public int dragBeanIndex() {
if (draggedBean != null) {
return mBeans.indexOf(draggedBean);
}
return -1;
}
@Override
public void onClick(View v) {
String str = ((Bean) v.getTag(R.id.id_bean_)).getStr();
Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();
}
public static class ViewH extends RecyclerView.ViewHolder {
private View icon;
private ImageView img;
private TextView tv;
public ViewH(View itemView) {
super(itemView);
icon = itemView.findViewById(R.id.item_icon);
img = ((ImageView) itemView.findViewById(R.id.item_img));
tv = ((TextView) itemView.findViewById(R.id.item_tv));
}
}
}
public class DragParent extends RelativeLayout implements PreDragListener {
private ImageView mImg;//在DragParent 跟随拖拽的img
DraggingListener mListener;
private Bitmap mDrawingCache;//mImg 使用的从item获取到的图像
public void setListener(DraggingListener listener) {
mListener = listener;
}
public DragParent(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (isDragged) {
//当处于拖拽状态下 Move时
int width = mImg.getWidth();
int height = mImg.getHeight();
//设置 mImg位置
mImg.setX(x - width / 2);
mImg.setY(y - height / 2);
//把位置信息回调给 DragGridView 完成计算
if (mListener != null) {
mListener.dragging(x, y);
}
return true;
}
break;
case MotionEvent.ACTION_UP:
if (isDragged) {
//把拖拽结束 告知 DragGridView
if (mListener != null) {
mListener.dragEnd();
}
//移除 拖拽的img
removeView(mImg);
//释放Bitmap
mDrawingCache.recycle();
//重置拖拽状态
isDragged = false;
return true;
}
break;
}
return super.dispatchTouchEvent(ev);
}
/**
* 是否处于拖拽状态
*/
boolean isDragged;
@Override
public void preDrag(View view) {
isDragged = true;
float x = view.getX();
float y = view.getY();
view.buildDrawingCache();
mDrawingCache = view.getDrawingCache();
mImg = new ImageView(getContext());
mImg.setImageBitmap(mDrawingCache);
mImg.setBackgroundColor(Color.BLUE);
mImg.setPadding(1, 1, 1, 1);
mImg.setX(x);
mImg.setY(y);
addView(mImg);
}
}
public class DragGridView extends RecyclerView implements DraggingListener {
public DragGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
int msHeight = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthSpec, msHeight);
}
/**
* 计算当前拖拽点 位于 DragGridView 那个item上
*/
public int nearToPosition(float x, float y) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
if (x >= view.getX() && x <= view.getX() + view.getWidth()
&& y >= view.getY() && y <= view.getY() + view.getHeight()) {
return ((DragAdapter) getAdapter()).mBeans.indexOf(view.getTag(R.id.id_bean_));
}
}
return -1;
}
//***接口回调 DragParent 处于拖拽中,把其拖拽点 传给DragGridView
@Override
public void dragging(float x, float y) {
//获取拖拽点所在的item位置
int position = nearToPosition(x, y);
DragAdapter adapter = (DragAdapter) getAdapter();
//或者当前被拖拽数据Bean所在mBeans的位置
int dragBeanIndex = adapter.dragBeanIndex();
//如果 二个位置不一致,则说明原来的数据Bean需要被remove后从新insert到指定位置
if (position != dragBeanIndex && position != -1) {
adapter.mBeans.remove(dragBeanIndex);
adapter.notifyItemRemoved(dragBeanIndex);
adapter.mBeans.add(position, adapter.draggedBean);
adapter.notifyItemInserted(position);
}
}
/**
* 拖拽结束 调用 DragAdapter 的dragEnd().
*/
@Override
public void dragEnd() {
DragAdapter adapter = (DragAdapter) getAdapter();
adapter.dragEnd();
}
}
12.Activity 设置一下。
public class MainActivity extends AppCompatActivity {
private DragParent parent;
private DragGridView drag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parent = (DragParent) findViewById(R.id.parent);
drag = (DragGridView) findViewById(R.id.drag);
drag.setLayoutManager(new GridLayoutManager(this, 3));
DragAdapter dragAdapter = new DragAdapter(this);
dragAdapter.setListener(parent);
parent.setListener(drag);
drag.setAdapter(dragAdapter);
}
}
14. 所以只实现了拖拽,从新排序的功能~~供参考,完~~