DragGridViewEx.java文件:
package com.smiling.draggridview; /* * onInterceptTouchEvent() -> onItemLongClick() -> onTouchEvent()->ACTION_MOVE->ACTION_UP; * * */ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.GridView; import android.widget.ImageView;
//以下为自定义GridView控件; public class DragGridViewEx extends GridView{ private WindowManager windowManager;// windows窗口控制类 private WindowManager.LayoutParams windowParams;// 用于控制拖拽项的显示的参数 private ImageView dragImageView;// 被拖拽的项(item),其实就是一个ImageView\ private View itemView=null; private Bitmap bm; private ImageView imageView; private View dragger; private int dragSrcPosition;// 手指拖动项在列表中的原始位置 private int dragPosition;// 手指点击准备拖动的时候,当前拖动项在列表中的位置. private int dragPointX; private int dragPointY;// 在当前数据项中的位置 private int dragOffsetX; private int dragOffsetY;// 当前视图和屏幕的距离(这里只使用了y方向上) private int upScrollBounce;// 拖动的时候,开始向上滚动的边界 private int downScrollBounce;// 拖动的时候,开始向下滚动的边界 private int tempChangeId; private boolean isDoTouch = false; private boolean hasAdd=false; //========================================================================================================= public DragGridViewEx(Context context) { super(context); // TODO 自动生成的构造函数存根 } public DragGridViewEx(Context context, AttributeSet attrs) { super(context, attrs); // TODO 自动生成的构造函数存根 } public DragGridViewEx(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO 自动生成的构造函数存根 } //========================================================================================================== public void setDoTouch(boolean b){ this.isDoTouch=b; this.hasAdd=false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { { if (ev.getAction() == MotionEvent.ACTION_DOWN) { { int x = (int) ev.getX(); int y = (int) ev.getY(); this.tempChangeId=dragSrcPosition = dragPosition = pointToPosition(x, y); System.out.println("getY()="+y+","+"dragPosition="+dragPosition); System.out.println("getFirstVisiblePosition()="+getFirstVisiblePosition()); // 无效不进行处理 if (dragPosition == AdapterView.INVALID_POSITION) { return super.onInterceptTouchEvent(ev); } // 获取当前位置的视图(可见状态) itemView = getChildAt(dragPosition-getFirstVisiblePosition()); dragPointX = x - itemView.getLeft(); dragPointY = y - itemView.getTop(); //不可见的项不算; dragOffsetX = (int) (ev.getRawX() - x); dragOffsetY = (int) (ev.getRawY() - y); //每个项中可能有其他的文字之类的东西,所以要获取 R.id.drag_gridview_image; dragger = itemView.findViewById(R.id.drag_gridview_image); if (dragger != null &&dragPointX>dragger.getLeft() &&dragPointX<dragger.getRight() &&dragPointY>dragger.getTop() &&dragPointY<dragger.getBottom()) { upScrollBounce = getHeight() / 4; // 取得向上滚动的边际,大概为该控件的1/3 downScrollBounce = getHeight() * 3 / 4;// 取得向下滚动的边际,大概为该控件的2/3 System.out.println("Here...."); itemView.setDrawingCacheEnabled(true);// 开启cache. bm= Bitmap.createBitmap(itemView.getDrawingCache());// 根据cache创建一个新的bitmap对象. startDrag(bm, x, y);// 初始化影像; } } } } return super.onInterceptTouchEvent(ev); } private void startDrag(Bitmap bm, int x, int y) { // stopDrag(); /*** * 初始化window. */ windowParams = new WindowManager.LayoutParams(); windowParams.gravity = Gravity.TOP| Gravity.LEFT; windowParams.x = x - dragPointX + dragOffsetX; windowParams.y = y - dragPointY + dragOffsetY; //getTop()+dragOffset; windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需获取焦点 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受触摸事件 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持设备常开,并保持亮度不变。 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;// 窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容。 windowParams.windowAnimations = 0; imageView = new ImageView(getContext()); imageView.setImageBitmap(bm); windowManager = (WindowManager) getContext().getSystemService("window"); // windowManager.addView(imageView, windowParams); //注意不在这里添加; dragImageView = imageView; } //=========================================================================================================== /** * 触摸事件处理 */ @Override public boolean onTouchEvent(MotionEvent ev) { // item的view不为空,且获取的dragPosition有效 if (dragImageView!=null&&dragPosition != INVALID_POSITION && isDoTouch==true) { if(!this.hasAdd){ windowManager.addView(imageView, windowParams); this.hasAdd=true; } int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_UP: System.out.println("ACTION_UP"); if(!this.dragger.isShown()){ this.dragger.setVisibility(View.VISIBLE); System.out.println("VISIBLE"); } int upX = (int) ev.getX(); int upY = (int) ev.getY(); stopDrag(); onDrop(upX,upY); isDoTouch=false; //若没有这个,就不会触发onItemClick事件了 hasAdd=false; break; case MotionEvent.ACTION_MOVE: //System.out.println("ACTION_MOVE"); if(this.dragger.isShown()){ this.dragger.setVisibility(View.INVISIBLE); } int moveX = (int)ev.getX(); int moveY = (int) ev.getY(); onDrag(moveX,moveY); break; case MotionEvent.ACTION_DOWN: //longClick之后不会执行; System.out.println("ACTION_DOWN"); int downX = (int)ev.getX(); int downY = (int) ev.getY(); break; default: break; } return true; } return super.onTouchEvent(ev); } //======================================================================================================= public void onDrag(int x, int y) { if (dragImageView != null) { windowParams.alpha = 0.7f;// 透明度 windowParams.x = x - dragPointX + dragOffsetX; windowParams.y = y - dragPointY + dragOffsetY;// 移动y值.//记得要加上dragOffset,windowManager计算的是整个屏幕.(标题栏和状态栏都要算上) windowManager.updateViewLayout(dragImageView, windowParams);// 时时移动. } int tempPosition = pointToPosition(x, y); if (tempPosition != INVALID_POSITION) { dragPosition = tempPosition; } onChange(x,y); // 滚动 if (y < upScrollBounce || y > downScrollBounce) { // 使用setSelection来实现滚动 setSelection(dragPosition); } } public void onChange(int x,int y){ if(dragPosition<getAdapter().getCount()){ DragGVAdapter adapter = (DragGVAdapter)getAdapter(); if(this.tempChangeId!=this.dragPosition){ adapter.update(tempChangeId,dragPosition); this.tempChangeId=this.dragPosition; } } int tempPosition=pointToPosition(x,y); if(tempPosition!=INVALID_POSITION){ this.dragPosition=tempPosition; } } public void stopDrag() { if (dragImageView != null) { windowManager.removeView(dragImageView); dragImageView = null; } } public void onDrop(int x,int y) { // 数据交换 if (dragPosition < getAdapter().getCount()) { DragGVAdapter adapter = (DragGVAdapter)getAdapter(); adapter.lastUpdate(); } } }
DragGVAdapter.java文件:
package com.smiling.draggridview; import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; public class DragGVAdapter extends BaseAdapter{ private Context context; private ArrayList<Integer> arrayDrawables; private boolean isHide=false; private int endPosition=-1; public DragGVAdapter(Context c,ArrayList<Integer> pics){ this.context=c; this.arrayDrawables=pics; } @Override public int getCount() { // TODO 自动生成的方法存根 return this.arrayDrawables.size(); } @Override public Object getItem(int arg0) { // TODO 自动生成的方法存根 return null; } @Override public long getItemId(int arg0) { // TODO 自动生成的方法存根 return arg0; } @Override public View getView(int position, View v, ViewGroup vg) { // TODO 自动生成的方法存根 LayoutInflater inflater=LayoutInflater.from(context); v=inflater.inflate(R.layout.drag_gridview_item,null); System.out.println("POSITION="+position); //连续输出两次POSITION=0; if(position!=endPosition){ ImageView imageview=(ImageView)v.findViewById(R.id.drag_gridview_image); imageview.setImageResource(this.arrayDrawables.get(position)); imageview.setScaleType(ImageView.ScaleType.FIT_XY); }else if(position==endPosition){ ImageView imageview=(ImageView)v.findViewById(R.id.drag_gridview_image); imageview.setImageResource(this.arrayDrawables.get(position)); imageview.setScaleType(ImageView.ScaleType.FIT_XY); imageview.setVisibility(View.INVISIBLE); } return v; } public void update(int start, int down) { this.endPosition=down; System.out.println("END="+endPosition); int drawable_id = arrayDrawables.get(start); arrayDrawables.remove(start); arrayDrawables.add(down, drawable_id); notifyDataSetChanged(); } public void lastUpdate(){ this.endPosition=-1; notifyDataSetChanged(); } }
这里需要注意几点,首先是方法的执行顺序,是先onInterceptTouchEvent(),然后是onItemLongClick(),接着onTouchEvent(),ACTION_MOVE->ACTION_UP;注意映像应该在onTouchEvent方法中添加,而不能在onInterceptTouchEvent()方法中添加,否则GridView上下滑动也会出现映像。
Sumsang S4实测截图如下: