2011-09-11 35 views
5

Để hiểu câu hỏi này, first read how this method works.Trợ giúp với vấn đề ListView Android UI

Tôi cố gắng để thực hiện một kéo và thả ListView, nó sẽ không sao nhưng đã chạy vào một khối đường. Vì vậy, tôi không phải xử lý tất cả mọi thứ, tôi đang chặn (nhưng trở về sai) MotionEvents gửi đến ListView, cho phép nó xử lý di chuyển và các công cụ. Khi tôi muốn bắt đầu kéo một mục, tôi sau đó trả về true và xử lý tất cả các công cụ kéo. Mọi thứ đều hoạt động tốt ngoại trừ một điều. Kéo (kéo và thả) được bắt đầu khi nó được xác định rằng một báo chí dài như một xảy ra (trong onInterceptTouchEvent). Tôi nhận được cho hình ảnh mà tôi kéo xung quanh như vậy. itemPositition là chỉ mục của mục đã được chọn.

(bỏ qua phần không liên quan)

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

Vấn đề là, mDragImage là một màu đen rắn như thế này. A solid back bitmap

Nhưng, nếu tôi không để ListView xử lý bất cứ điều gì. Như trong, tôi bắt đầu kéo trên ACTION_DOWN và dừng lại trên ACTION_UP, trông mDragImage đã mong đợi (nhưng tôi rõ ràng là mất khả năng cuộn).

A good bitmap

Kể từ khi kéo được bắt đầu với một nền báo chí dài, ListView được trao cơ hội để làm những việc trước khi báo chí dài xảy ra. Đây là dự đoán của tôi là tại sao điều này lại xảy ra. Khi một mục được nhấn, nó được đánh dấu bởi ListView. Một nơi nào đó trong khi làm như vậy, nó là rối tung với bitmap. Vì vậy, khi tôi đi để có được nó, nó trong một trạng thái kỳ lạ (tất cả các màu đen).

Tôi thấy hai tùy chọn để sửa lỗi này, tôi cũng không biết cách thực hiện.

  1. Tạo hình ảnh từ đầu.

  2. Xử lý bản thân làm nổi bật (nếu đó là vấn đề).

Tùy chọn hai có vẻ tốt hơn với tôi, ngoại trừ việc tôi xem tài liệu và mã nguồn và không thể tìm hiểu cách thực hiện. Dưới đây là một số điều tôi đã làm/thử.

  • tôi đặt setOnItemClickListener(...)setOnItemSelectedListener (...) với một phương pháp rỗng (làm nổi bật vẫn xảy ra). (Trước khi bất cứ ai thấy nó, gọi setOnClickListener kết quả trong một lỗi runtime.)

  • Tôi cũng nhìn vào cố gắng để có được những ListView để thực hiện một mục mới (đối với phương án 2), nhưng không thể tìm thấy một cách.

  • Đã dành 45 phút xem qua mã nguồn và tài liệu cố gắng xác định nơi đánh dấu là xảy ra (Tôi chưa bao giờ tìm thấy nó).

Mọi sự trợ giúp khắc phục lỗi này sẽ được đánh giá cao.

(EDIT1 START)

Vì vậy, tôi không thực sự biết nếu onLongClickListener đang làm việc, tôi đã thực hiện một lỗi trước khi nghĩ đến nó là gì. Tôi đang cố gắng thiết lập ngay bây giờ, sẽ cập nhật khi tôi tìm hiểu xem nó có hoạt động không.

(EDIT1 END)

Chỉnh sửa phút trước trước khi đăng bài. Tôi đã thử sử dụng onLongClickListener ngay bây giờ và hình ảnh là tốt. Tôi vẫn muốn biết nếu có một cách khác. Làm thế nào tôi phải sử dụng onLongClickListener để có được những thứ làm việc xấu xí, nhưng nó hoạt động. Tôi cũng đã dành rất nhiều thời gian để tìm ra điều này, thật tuyệt khi tìm ra câu trả lời. Tôi vẫn muốn có thể thay đổi/xử lý màu đánh dấu, màu cam mặc định không đẹp. Oh và xin lỗi về độ dài của bài đăng. Tôi không thể nghĩ ra cách để làm cho nó ngắn hơn, trong khi cung cấp tất cả các thông tin tôi nghĩ là cần thiết.

Trả lời

0

sử dụng mã này, nó cho phép ma túy hoạt động và thả trong 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; 
     } 

    } 
} 
Các vấn đề liên quan