Android Open Source - DragNDropList Drag N Drop List View






From Project

Back to project page DragNDropList.

License

The source code is released under:

Apache License

If you think the Android project DragNDropList listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2012 Terlici Ltd./*ww  w  .j  ava  2s  .  c om*/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.terlici.dragndroplist;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Adapter;
import android.widget.WrapperListAdapter;

import com.terlici.dragndroplist.DragNDropAdapter;

public class DragNDropListView extends ListView {
  
  public static interface OnItemDragNDropListener {
    public void onItemDrag(DragNDropListView parent, View view, int position, long id);
    public void onItemDrop(DragNDropListView parent, View view, int startPosition, int endPosition, long id);
  }
  
  boolean mDragMode;

  WindowManager mWm;
  int mStartPosition = INVALID_POSITION;
  int mDragPointOffset; // Used to adjust drag view location
  int mDragHandler = 0;
  
  ImageView mDragView;
  
  OnItemDragNDropListener mDragNDropListener;

  private void init() {
    mWm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
  }
  
  public DragNDropListView(Context context) {
    super(context);

    init();
  }
  
  public DragNDropListView(Context context, AttributeSet attrs) {
    super(context, attrs);

    init();
  }
  
  public DragNDropListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    init();
  }
  
  public void setOnItemDragNDropListener(OnItemDragNDropListener listener) {
    mDragNDropListener = listener;
  }
  
  public void setDragNDropAdapter(DragNDropAdapter adapter) {
    mDragHandler = adapter.getDragHandler();
    setAdapter(adapter);
  }
  
  /**
   * If the motion event was inside a handler view.
   *  
   * @param ev
   * @return true if it is a dragging move, false otherwise.
   */
  public boolean isDrag(MotionEvent ev) {
    if (mDragMode) return true;
    if (mDragHandler == 0) return false;
    
    int x = (int)ev.getX();
    int y = (int)ev.getY();
    
    int startposition = pointToPosition(x,y);
    
    if (startposition == INVALID_POSITION) return false;
    
    int childposition = startposition - getFirstVisiblePosition();
    View parent = getChildAt(childposition);
    View handler = parent.findViewById(mDragHandler);
    
    if (handler == null) return false;
    
    int top = parent.getTop() + handler.getTop();
    int bottom = top + handler.getHeight();
    int left = parent.getLeft() + handler.getLeft();
    int right = left + handler.getWidth();
    
    return left <= x && x <= right && top <= y && y <= bottom;
  }
  
  public boolean isDragging() {
    return mDragMode;
  }
  
  public View getDragView() {
    return mDragView;
  }
  
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    final int action = ev.getAction();
    final int x = (int)ev.getX();
    final int y = (int)ev.getY();
    
    
    if (action == MotionEvent.ACTION_DOWN && isDrag(ev)) mDragMode = true;

        if (!mDragMode || !isDraggingEnabled) return super.onTouchEvent(ev);

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        mStartPosition = pointToPosition(x, y);
        
        if (mStartPosition != INVALID_POSITION) {
          int childPosition = mStartPosition - getFirstVisiblePosition();
                    mDragPointOffset = y - getChildAt(childPosition).getTop();
                    mDragPointOffset -= ((int)ev.getRawY()) - y;
                    
          startDrag(childPosition, y);
          drag(0, y);
        }
        
        break;
      case MotionEvent.ACTION_MOVE:
        drag(0, y);
        break;
      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
      default:
        mDragMode = false;
        

        if (mStartPosition != INVALID_POSITION) {
          // check if the position is a header/footer
          int actualPosition =  pointToPosition(x,y);
          if (actualPosition > (getCount() - getFooterViewsCount()) - 1)
            actualPosition = INVALID_POSITION;

          stopDrag(mStartPosition - getFirstVisiblePosition(), actualPosition);
        }
        break;
    }
    
    return true;
  }
  
  /**
   * Prepare the drag view.
   * 
   * @param childIndex
   * @param y
   */
  private void startDrag(int childIndex, int y) {
    View item = getChildAt(childIndex);
    
    if (item == null) return;

    long id = getItemIdAtPosition(mStartPosition);

    if (mDragNDropListener != null)
          mDragNDropListener.onItemDrag(this, item, mStartPosition, id);

        Adapter adapter = getAdapter();
        DragNDropAdapter dndAdapter;

        // if exists a footer/header we have our adapter wrapped
        if (adapter instanceof WrapperListAdapter) {
            dndAdapter = (DragNDropAdapter)((WrapperListAdapter)adapter).getWrappedAdapter();
        } else {
            dndAdapter = (DragNDropAdapter)adapter;
        }

        dndAdapter.onItemDrag(this, item, mStartPosition, id);

    item.setDrawingCacheEnabled(true);
    
        // Create a copy of the drawing cache so that it does not get recycled
        // by the framework when the list tries to clean up memory
        Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
        
        WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams();
        mWindowParams.gravity = Gravity.TOP;
        mWindowParams.x = 0;
        mWindowParams.y = y - mDragPointOffset;

        mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        mWindowParams.format = PixelFormat.TRANSLUCENT;
        mWindowParams.windowAnimations = 0;
        
        Context context = getContext();
        ImageView v = new ImageView(context);
        v.setImageBitmap(bitmap);

        mWm.addView(v, mWindowParams);
        mDragView = v;
        
        item.setVisibility(View.INVISIBLE);
        item.invalidate(); // We have not changed anything else.
  }
  
  /**
   * Release all dragging resources.
   * 
   * @param childIndex
   */
  private void stopDrag(int childIndex, int endPosition) {
    if (mDragView == null) return;

    View item = getChildAt(childIndex);

        if (endPosition != INVALID_POSITION) {
            long id = getItemIdAtPosition(mStartPosition);

            if (mDragNDropListener != null)
                mDragNDropListener.onItemDrop(this, item, mStartPosition, endPosition, id);

            Adapter adapter = getAdapter();
            DragNDropAdapter dndAdapter;

            // if exists a footer/header we have our adapter wrapped
            if (adapter instanceof WrapperListAdapter) {
                dndAdapter = (DragNDropAdapter)((WrapperListAdapter)adapter).getWrappedAdapter();
            } else {
                dndAdapter = (DragNDropAdapter)adapter;
            }

            dndAdapter.onItemDrop(this, item, mStartPosition, endPosition, id);
        }
    
        mDragView.setVisibility(GONE);
        mWm.removeView(mDragView);
        
        mDragView.setImageDrawable(null);
        mDragView = null;
        
        item.setDrawingCacheEnabled(false);
        item.destroyDrawingCache();
        
        item.setVisibility(View.VISIBLE);
        
        mStartPosition = INVALID_POSITION;
        
        invalidateViews(); // We have changed the adapter data, so change everything
  }
  
  /**
   * Move the drag view.
   * 
   * @param x
   * @param y
   */
  private void drag(int x, int y) {
    if (mDragView == null) return;

    WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams)mDragView.getLayoutParams();
    layoutParams.x = x;
    layoutParams.y = y - mDragPointOffset;

    mWm.updateViewLayout(mDragView, layoutParams);
  }

    private boolean isDraggingEnabled = true;

    public void setDraggingEnabled(boolean draggingEnabled)
    {
        this.isDraggingEnabled = draggingEnabled;
    }
}




Java Source Code List

com.terlici.dragndroplist.DragNDropAdapter.java
com.terlici.dragndroplist.DragNDropCursorAdapter.java
com.terlici.dragndroplist.DragNDropListView.java
com.terlici.dragndroplist.DragNDropSimpleAdapter.java