Android UI - GridView长按实现拖拽效果

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实测截图如下:

Android UI - GridView长按实现拖拽效果_第1张图片Android UI - GridView长按实现拖拽效果_第2张图片

你可能感兴趣的:(android,UI,GridView,拖拽)