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

来源:互联网 发布:网络平台运营方案 编辑:程序博客网 时间:2024/06/16 16:25

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进行绑定用的。

<?xml version="1.0" encoding="utf-8"?><resources>    <item name="id_bean_" type="id"/></resources>
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<DragAdapter.ViewH> implements View.OnLongClickListener, View.OnClickListener {    Context mContext;    public List<Bean> 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. 所以只实现了拖拽,从新排序的功能~~供参考,完~~




0 0
原创粉丝点击