【问题标题】:android scroll while drag & dropandroid在拖放时滚动
【发布时间】:2011-07-22 14:42:04
【问题描述】:

您好,我正在尝试在 ListView 上进行拖放操作。它工作得很好。但我失去了点击和滚动的能力。我如何保留这两个?我认为拖放应该在长按项目而不是正常按下时发生。这是我的 onTouch,它位于扩展 ListView 的 MyListView 中

@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 && x < this.getWidth()/4) {
            this._dragMode = true;
        }

        if (!this._isDragNDrop) 
            return super.onTouchEvent(ev);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                this._startPosition = pointToPosition(x,y);
                if (this._startPosition != INVALID_POSITION) {
                    int mItemPosition = this._startPosition - getFirstVisiblePosition();
                    this._dragPointOffset = y - getChildAt(mItemPosition).getTop();
                    this._dragPointOffset -= ((int)ev.getRawY()) - y;
                    startDrag(mItemPosition,y);
                    drag(x,y);
                }   
                break;
            case MotionEvent.ACTION_MOVE:
                drag(x,y);
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
            default:
                this._dragMode = false;
                //_isDragNDrop = false;
                this._endPosition = pointToPosition(x,y);
                stopDrag(this._startPosition - getFirstVisiblePosition());
                if (this._dropListener != null && this._startPosition != INVALID_POSITION && this._endPosition != INVALID_POSITION) 
                    this._dropListener.onDrop(this._startPosition, this._endPosition);
                break;
        }
        return true;
    }

【问题讨论】:

    标签: android listview drag-and-drop


    【解决方案1】:

    我刚刚在我的应用程序中实现了拖放列表视图,通过长按一个项目开始拖动。

    源代码在 GitHub 上:DraggableListView,我有一个blog post 来描述它。希望对你有帮助。

    【讨论】:

    • 哇,非常感谢!我们决定推迟此功能,因为我们无法使其正常工作。我会看看这个,看看这是否能解决我的问题。我看到了你的博客,确实需要一个多星期的时间,因为当我转入两天时,我不得不放弃它:)
    • 很棒的组件!对我来说很好...... THX
    • 上面的博文链接无效,但您可以在此处找到所需的其余内容:codegarage.no-ip.co.uk/snippets/94
    • 我已经更新了答案中的链接。谢谢@mpemburn
    【解决方案2】:

    我正在实现类似的东西。 希望这对其他人有所帮助,因为我仍在解决问题。

    ...
    thumb.setOnDragListener(new Drag());
    ...
    
    public class Drag implements OnDragListener{
    public static int PositionOfDraggedItem = -1;
          public int PositionOfItemDraggedOver = -1;
    
    public Drag() {}
    
    @Override
    public boolean onDrag(View v, DragEvent event)
    {
        final int action = event.getAction();
        boolean state = true;
    
        View root = v.getRootView();
        ListView List = (ListView) root.findViewById(android.R.id.list);
        Object holder = v.getTag() instanceof OrderHolder? (OrderHolder)v.getTag() : v.getTag();
    
        String BookId = holder instanceof OrderHolder? String.valueOf(((OrderHolder)holder).id) : (String)holder;
    
        switch(action)
        {
            case DragEvent.ACTION_DRAG_STARTED:
    
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                if( PositionOfDraggedItem != -1 )
                {
                    if( this.PositionOfItemDraggedOver != PositionOfDraggedItem )
                    {
                        if( v.getBackground() != null )
                            v.setBackgroundDrawable(v.getContext().getResources().getDrawable(drawable.row_ovr));
                    }
                }
                break;
            case DragEvent.ACTION_DRAG_LOCATION:
                /**
                 * Set the item being
                 * here, as it will not
                 * provide location data
                 * anywhere else
                 */
                if( PositionOfDraggedItem == -1 )
                    PositionOfDraggedItem = List.getPositionForView(v);
    
                /**
                 * Set the view thats
                 * being dragged over
                 */
                this.PositionOfItemDraggedOver = List.getPositionForView(v);
    
                int PositionOfLastVisibleView = List.getLastVisiblePosition();
                int PositionOfFirstVisibleView = List.getFirstVisiblePosition();
    
                if( this.PositionOfItemDraggedOver != -1 && ( this.PositionOfItemDraggedOver != PositionOfDraggedItem ) ){
                    if( this.PositionOfItemDraggedOver == PositionOfLastVisibleView-1 || this.PositionOfItemDraggedOver == PositionOfLastVisibleView || this.PositionOfItemDraggedOver == PositionOfLastVisibleView+1 ){
                        List.smoothScrollToPosition(PositionOfLastVisibleView+1);
                    }else if( this.PositionOfItemDraggedOver == PositionOfFirstVisibleView-1 || this.PositionOfItemDraggedOver == PositionOfFirstVisibleView+1 || this.PositionOfItemDraggedOver == PositionOfFirstVisibleView ){
                        List.smoothScrollToPosition(PositionOfFirstVisibleView-1);
                    }
                }
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                if( v.getBackground() != null )
                    v.setBackgroundDrawable(v.getContext().getResources().getDrawable(drawable.row));
                break;
            case DragEvent.ACTION_DROP:
                if(event != null)
                {
                    ClipData data = event.getClipData();
                    if( data != null && data.getItemCount() > 0 )
                    {
                        if( !data.getItemAt(0).getText().toString().equalsIgnoreCase(BookId) )
                        {
                            if( v.getBackground() != null )
                                v.setBackgroundDrawable(v.getContext().getResources().getDrawable(drawable.row));
                            /**
                             * Ordering info for
                             * book being dragged
                             */
                            String oShelfOrder = BookManager.item(v.getContext().getContentResolver(), dbhelper.BOOKS_SHELFORDER, 
                                    booksprovider.GetUri(dbhelper.BOOKS), Long.parseLong(data.getItemAt(0).getText().toString()));
                            String oBookOrder = BookManager.item(v.getContext().getContentResolver(), dbhelper.BOOKS_BOOKSORDER, 
                                    booksprovider.GetUri(dbhelper.BOOKS), Long.parseLong(data.getItemAt(0).getText().toString()));
    
                            /**
                             * Ordering info
                             * for book being dragged
                             * to
                             */
                            String dShelfOrder = BookManager.item(v.getContext().getContentResolver(), dbhelper.BOOKS_SHELFORDER, 
                                    booksprovider.GetUri(dbhelper.BOOKS), Long.parseLong(BookId));
                            String dBookOrder = BookManager.item(v.getContext().getContentResolver(), dbhelper.BOOKS_BOOKSORDER, 
                                    booksprovider.GetUri(dbhelper.BOOKS), Long.parseLong(BookId));
    
                            /**
                             * Update book being dragged
                             */
                            ContentValues args = new ContentValues();
                            args.put(dbhelper.BOOKS_SHELFORDER, dShelfOrder);
                            args.put(dbhelper.BOOKS_BOOKSORDER, dBookOrder);
                            BookManager.updateBook(v.getContext().getContentResolver(), data.getItemAt(0).getText().toString(), args);
    
                            /**
                             * Update book being dragged to
                             */
                            ContentValues values = new ContentValues();
                            values.put(dbhelper.BOOKS_SHELFORDER, oShelfOrder);
                            values.put(dbhelper.BOOKS_BOOKSORDER, oBookOrder);
                            BookManager.updateBook(v.getContext().getContentResolver(), BookId, values);
    
                            if( v.getContext() instanceof OrderBooks ){
                                ((OrderBooks)v.getContext()).adapter.refresh();
                                ((OrderBooks)v.getContext()).adapter.notifyDataSetChanged();
    
                                PositionOfDraggedItem = -1;
                            }
                        }
                    }
                }
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                if( event != null && event.getResult())
                {
                    v.invalidate();
                }
                break;
        }
        return state;
    }
    

    }

    有一段时间没做这个了,更新以反映最新的变化。

    【讨论】:

    • smoothScrollToPosition 每次都会启动一个滚动动画,我认为最好的方法是每 1 秒发布一个 smoothScrollToPosition(amount, linear) ,但是这种方法不是公共的或受保护的......
    • 此解决方案可以完美滚动,但是,列表中在滚动之前不可见的视图的 DragListeners 在拖动时不会做出反应。当我将对象拖到列表视图的下部区域时,它会向下滚动,但通过滚动可见的视图上的 DragListener 不会收到任何事件。当我无需滚动即可到达它们时,它们照常工作。你们有没有为此想出解决方案?
    【解决方案3】:

    查看此question 以获得更多帮助。我还有一个名为 DragSortListView 的组件,我花了很长时间改进它。你可以在这里找到它:

    我可以帮助您将长按启动的拖动集成到我上述 repo 的一个分支中。

    【讨论】:

    • 酷库:)
    【解决方案4】:

    我实施了这个对我有用的解决方案。以下方法在我的 Activity 中,当 dragEvent 为 ACTION_DRAG_ENTERED 时,它在我的 dragEventListener 中调用。我声明的一些属性:

    //first visible item (getFirstVisiblePosition() does not work for me)
    int firstVisible;
    //number of scrolls
    int nbrScroll;
    //my listview to scroll
    ListView mListView;
    //the adapter of my listview
    SimpleAdapter mAdapter;
    

    ...

    public void scrollDrag(int position) {
                //this is the position of the item in my listview
                //to scroll down
                //test if the item entered is the last visible
        if (position == mListView.getLastVisiblePosition()
                && id < mListView.getCount()) {
            mAdapter.notifyDataSetChanged();
            mRightDrawerList.post(new Runnable() {
                @Override
                public void run() {
                    //scroll down
                    mListView.smoothScrollToPosition(mListView
                            .getLastVisiblePosition() + 1);
                    firstVisible++;
                }
            });
                //to scroll up
                //test if the item entered is the first visible
        } else if (position == firstVisible && position !=0) {
            mAdapter.notifyDataSetChanged();
            mListView.post(new Runnable() {
                @Override
                public void run() {
                    //scroll up
                    mListView.smoothScrollToPosition(firstVisible-1);
                    firstVisible --;
                }
            });
        }
    }
    

    希望对某人有所帮助。

    【讨论】:

      【解决方案5】:

      在 Kotlin 中:

      holder.mView.setOnDragListener { v, event ->
          when (event.action) {
              DragEvent.ACTION_DRAG_ENTERED -> {
                  ...
              }
              DragEvent.ACTION_DRAG_EXITED, DragEvent.ACTION_DRAG_ENDED -> {
                  ...
                  val y = calculateY(holder.mView)
                  val minY = calculateY(scroll_view) + 200
      
                  val scrollBounds = Rect() 
                  scroll_view.getHitRect(scrollBounds) //TODO: calculate only once
      
                  val maxY = minY + scrollBounds.height() - 400
                  if (y < minY) {
                      scroll_view?.post {
                          scroll_view.smoothScrollBy(0, -200)
                      }
                  } else if (y > maxY) {
                      scroll_view?.post {
                          scroll_view.smoothScrollBy(0, +200)
                      }
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        伙计们,我对 rickey 的代码做了一点改动,这对我有用。

        if (PositionOfItemDraggedOver == PositionOfLastVisibleView)
            order_item_list_lv.smoothScrollToPosition(PositionOfLastVisibleView + 1);
        
        if (PositionOfItemDraggedOver == PositionOfFirstVisibleView)
           order_item_list_lv.smoothScrollToPosition(PositionOfFirstVisibleView - 1);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-18
          • 1970-01-01
          • 2013-11-20
          • 2010-10-14
          相关资源
          最近更新 更多