2011-09-11 129 views
5

要理解这个问题,first read how this method works.帮助与Android UI的ListView问题

我试图实现拖放ListView,它会好起来,但遇到了 路障。所以我不必处理所有事情,我正在拦截(但返回false)MotionEvents发送到ListView,让它处理滚动和东西。当我想要开始拖动一个项目时,我会返回true并处理所有拖动的东西。除了一件事以外,一切工作都很好。当确定发生长按时(在onInterceptTouchEvent中),拖动(拖放)开始。我得到为我像这样拖动的图像。 itemPositition是所选项目的索引。

(省略不相关部分)

... 
View dragItem = mListView.getChildAt(itemPosition); 
dragItem.setDrawingCacheEnabled(true); 
Bitmap bitmap = Bitmap.createBitmap(dragItem.getDrawingCache()); 
mDragImage = new ImageView(mContext); 
mDragImage.setImageBitmap(bitmap); 
... 

问题是,mDragImage是一个实心黑像这样。 A solid back bitmap

但是,如果我不让ListView处理任何东西。在中,我开始拖动ACTION_DOWN并停止在ACTION_UP,mDragImage看起来有望(但我显然失去了滚动功能)。

A good bitmap

由于阻力开始长按,ListView控件的机会长按发生之前做的事情。这是我的猜测,为什么会发生这种情况。当一个项目被按下时,它被ListView突出显示。在这样做的地方,它正在搞乱位图。所以当我去了解它,它处于一个奇怪的状态(全黑)。

我看到两个选项来解决这个问题,我都不知道该怎么做。

  1. 从头开始创建图像。

  2. 处理自己突出显示(如果这是问题)。

对我来说,选项2似乎更好,除了我查看了文档和源代码,并且无法找到如何执行此操作。这是我已经完成/尝试的一些事情。

  • 我用空方法(突出 仍然发生)设置setOnItemClickListener(...)setOnItemSelectedListener(...)。 (之前有人建议它,调用 setOnClickListener导致运行错误。)

  • 我也看了成试图让ListView控件,使一个新的项目 (选项2),但无法找到一个方法。

  • 花了45分钟看源代码和 文档试图找出突出显示的位置 发生(我从来没有发现它)。

任何帮助解决这个问题将不胜感激。

(EDIT1 START)

所以,我真的不知道,如果onLongClickListener工作,我想这是以前犯了一个错误。我正在尝试设置它,当我发现它是否会更新。

(END EDIT1)后前

最后一刻修改。我刚刚尝试使用onLongClickListener,图像很好。我仍然想知道是否有另一种方式。我如何使用onLongClickListener来使事情工作是丑陋的,但它的工作原理。我花了很多时间试图找出答案,很高兴找到答案。我仍然希望能够改变/处理突出显示的颜色,默认的橙色不是很漂亮。哦,对于帖子的长度感到抱歉。我想不出让它变短的方法,同时提供我认为需要的所有信息。

回答

0

使用此代码,它可以让操作药物和下降的ListView:

public class DraggableListView extends ListView { 

    private static final String LOG_TAG = "tasks365"; 

    private static final int END_OF_LIST_POSITION = -2; 

    private DropListener mDropListener; 
    private int draggingItemHoverPosition; 
    private int dragStartPosition; // where was the dragged item originally 
    private int mUpperBound; // scroll the view when dragging point is moving out of this bound 
    private int mLowerBound; // scroll the view when dragging point is moving out of this bound 
    private int touchSlop; 
    private Dragging dragging; 
    private GestureDetector longPressDetector; 

    public DraggableListView(Context context, AttributeSet attrs) { 
     this(context, attrs, android.R.attr.listViewStyle); 
    } 

    public DraggableListView(final Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 

     touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 

     longPressDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() { 
      @Override 
      public void onLongPress(final MotionEvent e) { 
       int x = (int) e.getX(); 
       final int y = (int) e.getY(); 

       int itemnum = pointToPosition(x, y); 
       if (itemnum == AdapterView.INVALID_POSITION) { 
        return; 
       } 

       if (dragging != null) { 
        dragging.stop(); 
        dragging = null; 
       } 

       final View item = getChildAt(itemnum - getFirstVisiblePosition()); 
       item.setPressed(false); 
       dragging = new Dragging(getContext()); 
       dragging.start(y, ((int) e.getRawY()) - y, item); 
       draggingItemHoverPosition = itemnum; 
       dragStartPosition = draggingItemHoverPosition; 

       int height = getHeight(); 
       mUpperBound = Math.min(y - touchSlop, height/3); 
       mLowerBound = Math.max(y + touchSlop, height * 2/3); 
      } 
     }); 

     setOnItemLongClickListener(new OnItemLongClickListener() { 
      @SuppressWarnings("unused") 

      public boolean onItemLongClick(AdapterView<?> paramAdapterView, View paramView, int paramInt, long paramLong) { 
       // Return true to let AbsListView reset touch mode 
       // Without this handler, the pressed item will keep highlight. 
       return true; 
      } 
     }); 
    } 

    /* pointToPosition() doesn't consider invisible views, but we need to, so implement a slightly different version. */ 
    private int myPointToPosition(int x, int y) { 
     if (y < 0) { 
      return getFirstVisiblePosition(); 
     } 
     Rect frame = new Rect(); 
     final int count = getChildCount(); 
     for (int i = 0; i < count; i++) { 
      final View child = getChildAt(i); 
      child.getHitRect(frame); 
      if (frame.contains(x, y)) { 
       return getFirstVisiblePosition() + i; 
      } 
     } 
     if ((x >= frame.left) && (x < frame.right) && (y >= frame.bottom)) { 
      return END_OF_LIST_POSITION; 
     } 
     return INVALID_POSITION; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     if (longPressDetector.onTouchEvent(ev)) { 
      return true; 
     } 

     if ((dragging == null) || (mDropListener == null)) { 
      // it is not dragging, or there is no drop listener 
      return super.onTouchEvent(ev); 
     } 

     int action = ev.getAction(); 
     switch (ev.getAction()) { 

     case MotionEvent.ACTION_UP: 
     case MotionEvent.ACTION_CANCEL: 
      dragging.stop(); 
      dragging = null; 

      if (mDropListener != null) { 
       if (draggingItemHoverPosition == END_OF_LIST_POSITION) { 
        mDropListener.drop(dragStartPosition, getCount() - 1); 
       } else if (draggingItemHoverPosition != INVALID_POSITION) { 
        mDropListener.drop(dragStartPosition, draggingItemHoverPosition); 
       } 
      } 
      resetViews(); 
      break; 

     case MotionEvent.ACTION_DOWN: 
     case MotionEvent.ACTION_MOVE: 
      int x = (int) ev.getX(); 
      int y = (int) ev.getY(); 
      dragging.drag(x, y); 
      int position = dragging.calculateHoverPosition(); 
      if (position != INVALID_POSITION) { 
       if ((action == MotionEvent.ACTION_DOWN) || (position != draggingItemHoverPosition)) { 
        draggingItemHoverPosition = position; 
        doExpansion(); 
       } 
       scrollList(y); 
      } 
      break; 
     } 
     return true; 
    } 

    private void doExpansion() { 
     int expanItemViewIndex = draggingItemHoverPosition - getFirstVisiblePosition(); 
     if (draggingItemHoverPosition >= dragStartPosition) { 
      expanItemViewIndex++; 
     } 

     // Log.v(LOG_TAG, "Dragging item hovers over position " + draggingItemHoverPosition + ", expand item at index " 
     //  + expanItemViewIndex); 

     View draggingItemOriginalView = getChildAt(dragStartPosition - getFirstVisiblePosition()); 
     for (int i = 0;; i++) { 
      View itemView = getChildAt(i); 
      if (itemView == null) { 
       break; 
      } 
      ViewGroup.LayoutParams params = itemView.getLayoutParams(); 
      int height = LayoutParams.WRAP_CONTENT; 
      if (itemView.equals(draggingItemOriginalView)) { 
       height = 1; 
      } else if (i == expanItemViewIndex) { 
       height = itemView.getHeight() + dragging.getDraggingItemHeight(); 
      } 
      params.height = height; 
      itemView.setLayoutParams(params); 
     } 
    } 

    /** 
    * Reset view to original height. 
    */ 
    private void resetViews() { 
     for (int i = 0;; i++) { 
      View v = getChildAt(i); 
      if (v == null) { 
       layoutChildren(); // force children to be recreated where needed 
       v = getChildAt(i); 
       if (v == null) { 
        break; 
       } 
      } 
      ViewGroup.LayoutParams params = v.getLayoutParams(); 
      params.height = LayoutParams.WRAP_CONTENT; 
      v.setLayoutParams(params); 
     } 
    } 

    private void resetScrollBounds(int y) { 
     int height = getHeight(); 
     if (y >= height/3) { 
      mUpperBound = height/3; 
     } 
     if (y <= height * 2/3) { 
      mLowerBound = height * 2/3; 
     } 
    } 

    private void scrollList(int y) { 
     resetScrollBounds(y); 

     int height = getHeight(); 
     int speed = 0; 
     if (y > mLowerBound) { 
      // scroll the list up a bit 
      speed = y > (height + mLowerBound)/2 ? 16 : 4; 
     } else if (y < mUpperBound) { 
      // scroll the list down a bit 
      speed = y < mUpperBound/2 ? -16 : -4; 
     } 
     if (speed != 0) { 
      int ref = pointToPosition(0, height/2); 
      if (ref == AdapterView.INVALID_POSITION) { 
       //we hit a divider or an invisible view, check somewhere else 
       ref = pointToPosition(0, height/2 + getDividerHeight() + 64); 
      } 
      View v = getChildAt(ref - getFirstVisiblePosition()); 
      if (v != null) { 
       int pos = v.getTop(); 
       setSelectionFromTop(ref, pos - speed); 
      } 
     } 
    } 

    public void setDropListener(DropListener l) { 
     mDropListener = l; 
    } 

    public interface DropListener { 
     void drop(int from, int to); 
    } 

    class Dragging { 

     private Context context; 
     private WindowManager windowManager; 
     private WindowManager.LayoutParams mWindowParams; 
     private ImageView mDragView; 
     private Bitmap mDragBitmap; 
     private int coordOffset; 
     private int mDragPoint; // at what offset inside the item did the user grab it 
     private int draggingItemHeight; 
     private int x; 
     private int y; 
     private int lastY; 

     public Dragging(Context context) { 
      this.context = context; 
      windowManager = (WindowManager) context.getSystemService("window"); 
     } 

     /** 
     * @param y 
     * @param offset - the difference in y axis between screen coordinates and coordinates in this view 
     * @param view - which view is dragged 
     */ 
     public void start(int y, int offset, View view) { 
      this.y = y; 
      lastY = y; 
      this.coordOffset = offset; 
      mDragPoint = y - view.getTop(); 

      draggingItemHeight = view.getHeight(); 

      mDragView = new ImageView(context); 
      mDragView.setBackgroundResource(android.R.drawable.alert_light_frame); 

      // 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 
      view.setDrawingCacheEnabled(true); 
      mDragBitmap = Bitmap.createBitmap(view.getDrawingCache()); 
      mDragView.setImageBitmap(mDragBitmap); 

      mWindowParams = new WindowManager.LayoutParams(); 
      mWindowParams.gravity = Gravity.TOP; 
      mWindowParams.x = 0; 
      mWindowParams.y = y - mDragPoint + coordOffset; 
      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; 
      mWindowParams.format = PixelFormat.TRANSLUCENT; 
      mWindowParams.windowAnimations = 0; 

      windowManager.addView(mDragView, mWindowParams); 
     } 

     public void drag(int x, int y) { 
      lastY = this.y; 
      this.x = x; 
      this.y = y; 
      mWindowParams.y = y - mDragPoint + coordOffset; 
      windowManager.updateViewLayout(mDragView, mWindowParams); 
     } 

     public void stop() { 
      if (mDragView != null) { 
       windowManager.removeView(mDragView); 
       mDragView.setImageDrawable(null); 
       mDragView = null; 
      } 
      if (mDragBitmap != null) { 
       mDragBitmap.recycle(); 
       mDragBitmap = null; 
      } 
     } 

     public int getDraggingItemHeight() { 
      return draggingItemHeight; 
     } 

     public int calculateHoverPosition() { 
      int adjustedY = (int) (y - mDragPoint + (Math.signum(y - lastY) + 2) * draggingItemHeight/2); 
      // Log.v(LOG_TAG, "calculateHoverPosition(): lastY=" + lastY + ", y=" + y + ", adjustedY=" + adjustedY); 
      int pos = myPointToPosition(0, adjustedY); 
      if (pos >= 0) { 
       if (pos >= dragStartPosition) { 
        pos -= 1; 
       } 
      } 
      return pos; 
     } 

    } 
}