Android 初步实现item可拖拽RecyclerView (Grid模式下)

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

8.DragParent 实现了PreDragListener,当DragAdapter 内部触发长按回调时 需要调用该接口告知 DragParent那个itemView 进入拖拽状态。

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


11.分别给出 DragParent  和 DragGridView 代码。

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



13.如果DragGridView数据过多 ,这里并没有实现拖拽到最上部或最下边是自动上拉、下拉DragGridView的功能。

14. 所以只实现了拖拽,从新排序的功能~~供参考,完~~




你可能感兴趣的:(Android 初步实现item可拖拽RecyclerView (Grid模式下))