網路上看了一些文章, 發現寫得感覺複雜化且動作不盡理想, 就自己來了, 實現拖曳功能幾個主要的重點都以在程式內說明, 但目前仍存在一個問題需要克服, 若要搭配 HorizontalScrollView 作橫移時, 會卡住
► 使用
► 使用
► DragGridViewDragGridView.useDragMode(true); DragGridView.setOnDragCellEvent(new OnDragCellEvent() { public void onEvent(AdapterView<?> view, Adapter adapter, int srcPosition, int tarPosition) { //拖曳 處理 } });
public class DragGridView extends GridView { public DragGridView(Context context, AttributeSet attrs) { super(context, attrs); } //啟用拖曳功能 private boolean dragMode = false;//是否使用拖曳 private int dragPosition; // 開始拖曳位置 private int dropPosition; // 結訴拖拽位置 private ImageView dragImage; // 拖曳時圖示 private WindowManager windowManager; private WindowManager.LayoutParams windowLayout; public void useDragMode(boolean mode) { dragMode = mode; if (!dragMode) return; // windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window" //拖曳視窗樣式設定 windowLayout = new WindowManager.LayoutParams(); windowLayout.gravity = Gravity.TOP | Gravity.LEFT; windowLayout.height = WindowManager.LayoutParams.WRAP_CONTENT; windowLayout.width = WindowManager.LayoutParams.WRAP_CONTENT; windowLayout.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; windowLayout.format = PixelFormat.TRANSLUCENT; windowLayout.alpha = 0.8f;// 透明度 //長按事件處理 this.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (!dragMode) return true; dragPosition = dropPosition = pointToPosition(mouseX, mouseY); if (dragPosition == AdapterView.INVALID_POSITION) return false; columnCount = getNumColumnsCompat(); ViewGroup itemView = (ViewGroup) getChildAt(dragPosition - getFirstVisiblePosition()); // 清除cache,生成圖示 itemView.destroyDrawingCache(); itemView.setDrawingCacheEnabled(true); startDrag( Bitmap.createBitmap(itemView.getDrawingCache()) ); return false; }; }); } int mouseX = 0, mouseY = 0; // GridView 座標系 int displayX = 0, displayY = 0; // 螢幕座標系 @Override public boolean onTouchEvent(MotionEvent ev) {// ev 的座標系是以 該元件 GridView 為基準 //Log.d("dd","onTouchEvent"); if (!dragMode) return super.onTouchEvent(ev); mouseX = (int) ev.getX(); mouseY = (int) ev.getY(); displayX = (int) ev.getRawX(); displayY = (int) ev.getRawY(); if ( (dragImage != null) && (dragPosition != AdapterView.INVALID_POSITION) ) { switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: onDrag(mouseX, mouseY); break; case MotionEvent.ACTION_UP: onDrop(mouseX, mouseY); break; } } if (dragImage != null)//拖曳過程需 false 否則不在預計的滾動區域內時仍會觸發畫面滾動 return false; else return super.onTouchEvent(ev); } int adjX = 0, adjY = 0; //調整圖像位置 private void startDrag(Bitmap bm) { stopDrag(); adjX = bm.getWidth() / 2;//視窗中心對準滑鼠 adjY = bm.getHeight() / 2; setDragWindowPos();// 設定顯示座標 dragImage = new ImageView(getContext()); dragImage.setImageBitmap(bm); windowManager.addView(dragImage, windowLayout); } private void setDragWindowPos() { windowLayout.x = displayX - adjX; windowLayout.y = displayY - adjY; if (dragImage != null) windowManager.updateViewLayout(dragImage, windowLayout); } private void onDrag(int x, int y) { setDragWindowPos(); int pos = this.pointToPosition(x, y); if (pos == AdapterView.INVALID_POSITION) return; int fs = this.getFirstVisiblePosition();//畫面上第一個cell位置 int ls = this.getLastVisiblePosition();//畫面上最後一個cell位置 if ( pos <= (fs + columnCount) ) {//上移 fs -= columnCount; this.smoothScrollToPosition(fs); } else if ( pos >= (ls - columnCount) ) {//下移 ls += columnCount; this.smoothScrollToPosition(ls); } } private void onDrop(int x, int y) {//拖曳放開 stopDrag(); if (mOnDragCellEvent==null) return; // dropPosition = pointToPosition(x, y); if ( (dropPosition!=AdapterView.INVALID_POSITION)&&(dropPosition != dragPosition) ) mOnDragCellEvent.onEvent(this, this.getAdapter(), dragPosition, dropPosition); } private void stopDrag() { adjX = adjY = 0; if (dragImage != null) { windowManager.removeView(dragImage); dragImage = null; } } //拖曳事件 OnDragCellEvent mOnDragCellEvent = null; public interface OnDragCellEvent { /** * @param view GridView. * @param adapter GridView Cell list. * @param srcPosition 拖曳開始cell位置. * @param tarPosition 拖曳結束cell位置. */ void onEvent(AdapterView<?> view, Adapter adapter, int srcPosition, int tarPosition); } public void setOnDragCellEvent(OnDragCellEvent event) { mOnDragCellEvent = event; } public final OnDragCellEvent getOnDragCellEvent() { return mOnDragCellEvent; } //自行計算欄位數 //this.getNumColumns(); API11以上才支援 private int columnCount = 1; private int getNumColumnsCompat() { int columns = 0; int children = getChildCount();//畫面上的cell數 if (children > 0) { int width = getChildAt(0).getMeasuredWidth();//每個 cell寬度 if (width > 0) { columns = getWidth() / width; } } return columns > 0 ? columns : AUTO_FIT; } }