实现可拖拽item的GridView

本文介绍了一种在Android中实现GridView项自由拖拽的方法。主要通过自定义BaseDragableAdapter来处理数据交换,并通过DragableGridView处理拖拽过程中的视觉效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前的工作中,需要实现一个功能就是GridView中的item可以自由拖动, 思考了一下,其实实现起来不是很困难,主要工作就是交换节点,以及拖动时的移动效果,下面讲讲具体的实现:
首先声明一个BaseAdapter:

package com.dafasoft.dragablegridview;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import java.util.ArrayList;
import java.util.List;
/**
 * Created by zhangyulong on 16/9/22.
 */
public abstract class BaseDragableAdapter<T> extends BaseAdapter {

    protected List<T> mList;
    protected Context mContext;
    protected LayoutInflater mInflater;
    //初始化需隐藏的位置信息
    protected int mHidePosition = AdapterView.INVALID_POSITION;

    public BaseDragableAdapter(Context context) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(context);
        mList = new ArrayList<T>();
    }

    @Override
    public int getCount() {
        return mList == null ? 0 : mList.size();
    }

    @Override
    public Object getItem(int i) {
        return mList == null ? 0 : mList.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public abstract View getView(int i, View view, ViewGroup viewGroup);

    public void setList(List<T> list) {
        if (this.mList != null) this.mList.clear(); // 避免脏数据
        if (list == null) {
            return;
        }
        this.mList = list;
    }

    public void setList(T[] list){
        ArrayList<T> arrayList = new ArrayList<T>(list.length);
        for (T t : list) {
            arrayList.add(t);
        }
        setList(arrayList);
    }

    public List<T> getList() {
        return this.mList;
    }

    public void addAll(List<T> list) {
        if (list == null || list.size() == 0) return;
        this.mList.addAll(list);
    }

    public void addAll(int location, List<T> list) {
        if (list == null || list.size() == 0) return;
        this.mList.addAll(location, list);
    }

    public void clean() {
        if (getCount() == 0) return;

        mList.clear();
    }

    public void hideView(int position){
        mHidePosition = position;
        notifyDataSetChanged();
    }

    public void showHideView(){
        //重置hideposition
        mHidePosition = AdapterView.INVALID_POSITION;
        notifyDataSetChanged();
    }

    /**
     * 交换节点
     * @param draggedPos 拖拽的起始节点
     * @param currentPos 拖拽的当前节点
     */
    public void swapView(int draggedPos , int currentPos) {
        //从前往后拖
        if(draggedPos < currentPos){
            //将被拖拽的节点移动至当前节点
            mList.add(currentPos + 1 , mList.get(draggedPos));
            //删除拖拽前的节点
            mList.remove(draggedPos);
        }
        //从后往前拖
        else if (draggedPos > currentPos) {
            //将被拖拽的节点移动至当前节点
            mList.add(currentPos , mList.get(draggedPos));
            //删除拖拽前的节点
            mList.remove(draggedPos + 1);
        }
        mHidePosition = currentPos;
        notifyDataSetChanged();
    }
}

其次实现DragableGridView:

package com.dafasoft.dragablegridview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;

/**
 * Created by zhangyulong on 16/9/22.
 */
public class DragableGridView extends GridView {
    private static final int DRAG_IMG_SHOW = 1;
    private static final int DRAG_IMG_NOT_SHOW = 0;
    private static final String LOG_TAG = "DragGridView";
    private static final float AMP_FACTOR = 1.2f;

    private ImageView dragImageView;
    private WindowManager.LayoutParams dragImageViewParams;
    private WindowManager windowManager;
    private boolean isViewOnDrag = false;

    /**previous dragged over position*/
    private int preDraggedOverPositon = AdapterView.INVALID_POSITION;
    private int downRawX;
    private int downRawY;


    public DragableGridView(Context context) {
        super(context);
        initView();
    }

    public DragableGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public DragableGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    public void initView() {
        setOnItemLongClickListener(mOnItemLongClickListener);
        //setOnItemClickListener(onItemClickListener);
        //setOnItemSelectedListener(onItemSelectedListener);
        //初始化显示被拖动item的image view
        dragImageView = new ImageView(getContext());
        dragImageView.setTag(DRAG_IMG_NOT_SHOW);
        //初始化用于设置dragImageView的参数对象
        dragImageViewParams = new WindowManager.LayoutParams();
        //获取窗口管理对象,用于后面向窗口中添加dragImageView
        windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    }

    private OnItemLongClickListener mOnItemLongClickListener = new OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
            //记录长按item位置
            preDraggedOverPositon = position;

            //获取被长按item的drawing cache
            view.destroyDrawingCache();
            view.setDrawingCacheEnabled(true);
            //通过被长按item,获取拖动item的bitmap
            Bitmap dragBitmap = Bitmap.createBitmap(view.getDrawingCache());

            //设置拖动item的参数
            dragImageViewParams.gravity = Gravity.TOP | Gravity.LEFT;
            //设置拖动item为原item 1.2倍
            dragImageViewParams.width = (int)(AMP_FACTOR*dragBitmap.getWidth());
            dragImageViewParams.height = (int)(AMP_FACTOR*dragBitmap.getHeight());
            //设置触摸点为绘制拖动item的中心
            dragImageViewParams.x = (downRawX - dragImageViewParams.width/2);
            dragImageViewParams.y = (downRawY - dragImageViewParams.height/2);
            dragImageViewParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
            //设置窗口支持透明度
            dragImageViewParams.format = PixelFormat.TRANSLUCENT;
            dragImageViewParams.windowAnimations = 0;

            //dragImageView为被拖动item的容器,清空上一次的显示
            if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {
                windowManager.removeView(dragImageView);
                dragImageView.setTag(DRAG_IMG_NOT_SHOW);
            }

            //设置本次被长按的item
            dragImageView.setImageBitmap(dragBitmap);

            //添加拖动item到屏幕
            windowManager.addView(dragImageView, dragImageViewParams);
            dragImageView.setTag(DRAG_IMG_SHOW);
            isViewOnDrag = true;

            //设置被长按item不显示
            ((BaseDragableAdapter)getAdapter()).hideView(position);
            return true;
        }
    };

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        //被按下时记录按下的坐标
        if(ev.getAction() == MotionEvent.ACTION_DOWN) {
            //获取触摸点相对于屏幕的坐标
            downRawX = (int)ev.getRawX();
            downRawY = (int)ev.getRawY();
        }
        //dragImageView处于被拖动时,更新dragImageView位置
        else if((ev.getAction() == MotionEvent.ACTION_MOVE) && (isViewOnDrag == true)) {
            Log.i(LOG_TAG, "" + ev.getRawX() + " " + ev.getRawY());
            //设置触摸点为dragImageView中心
            dragImageViewParams.x = (int)(ev.getRawX() - dragImageView.getWidth()/2);
            dragImageViewParams.y = (int)(ev.getRawY() - dragImageView.getHeight()/2);
            //更新窗口显示,移动dragImageView的位置
            windowManager.updateViewLayout(dragImageView, dragImageViewParams);
            //获取当前触摸点的item position
            int currDraggedPosition = pointToPosition((int)ev.getX(), (int)ev.getY());
            //如果当前停留位置item不等于上次停留位置的item,交换本次和上次停留的item
            if((currDraggedPosition != AdapterView.INVALID_POSITION) && (currDraggedPosition != preDraggedOverPositon)) {
                ((BaseDragableAdapter)getAdapter()).swapView(preDraggedOverPositon, currDraggedPosition);
                preDraggedOverPositon = currDraggedPosition;
            }
        }
        //释放dragImageView
        else if((ev.getAction() == MotionEvent.ACTION_UP) && (isViewOnDrag == true)) {
            ((BaseDragableAdapter)getAdapter()).showHideView();
            if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {
                windowManager.removeView(dragImageView);
                dragImageView.setTag(DRAG_IMG_NOT_SHOW);
            }
            isViewOnDrag = false;
        }
        return super.onTouchEvent(ev);
    }
}

实现一个adapter继承自BaseDragableAdapter:

package com.dafasoft.dragablegridview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by zhangyulong on 16/9/22.
 */
public class MyAdapter extends BaseDragableAdapter<String> {
    public MyAdapter(Context context) {
        super(context);
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder;
        if (view == null) {
            viewHolder = new ViewHolder();
            view = mInflater.inflate(R.layout.adapter_my , null);
            viewHolder.mItemTv = (TextView) view.findViewById(R.id.tv_item);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder)view.getTag();
        }
        if (mHidePosition == i) {
            view.setVisibility(View.GONE);
        } else {
            view.setVisibility(View.VISIBLE);
        }
        viewHolder.mItemTv.setText(mList.get(i));
        return view;
    }

    class ViewHolder{
        TextView mItemTv;
    }
}

在activity中使用:

package com.dafasoft.dragablegridview;

import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity {

    private DragableGridView mDragableGv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDragableGv = (DragableGridView) findViewById(R.id.drag_grid_view);
        MyAdapter adapter = new MyAdapter(this);
        List<String> list = new ArrayList<String>();
        for (int i = 0 ; i < 30 ; i ++) {
            list.add("position" + i);
        }
        adapter.setList(list);
        mDragableGv.setAdapter(adapter);
    }
}

代码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值