用户拖放项目时滚动ListView

时间:2015-05-21 13:08:49

标签: android android-listview scroll drag-and-drop

我有一个ListView mRecipeListView,其中包含许多项目。

listViewAdapter内,当它为要显示的项生成视图时,我添加了一个onLongClickListener来启动拖动操作:

view.setOnLongClickListener(new View.OnLongClickListener() {
  ClipData data = ClipData.newPlainText("", "");
  View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
  view.startDrag(data, shadowBuilder, view, 0);
  // Highlight dragged view.
  view.setBackgroundColor(getResources().getColor(R.color.app_color_accent));
  view.invalidate();
}

同一视图也会获得onDragListener,以便每个视图都是有效的放置目标。目标当然是通过拖放来重新排序视图:

view.setOnDragListener(new View.OnDragListener() {
  @Override
  public boolean onDrag(View view, DragEvent dragEvent) {
  switch (dragEvent.getAction()) {
    // ...
    // re-ordering works just fine
    // ...
    case DragEvent.ACTION_DRAG_LOCATION:                                   
      // y-coord of touch event inside the touched view (so between 0 and view.getBottom())
      float y = dragEvent.getY();
      // y-coord of top border of the view inside the current viewport.
      int viewTop = view.getTop();
      // y-coord that is still visible of the list view.
      int listBottom = mRecipeListView.getBottom(),
      listTop = mRecipeListView.getTop();

      // actual touch position on screen > bottom with 200px margin
      if (y + viewTop > listBottom - 200) {
        mRecipeListView.smoothScrollBy(100, 25);
        View child = mRecipeListView.getChildAt(mRecipeListView.getChildCount() - 1);
        child.setVisibility(View.GONE);
        child.setVisibility(View.VISIBLE);
      } else if (y + viewTop < listTop + 200) {
        mRecipeListView.smoothScrollBy(-100, 25);
        View child = mRecipeListView.getChildAt(0);  
        child.setVisibility(View.GONE);
        child.setVisibility(View.VISIBLE);
      }
      return true;
  }
}

因此,在ACTION_DROP_LOCATION的情况下,如果在有效的放置目标视图的边界框内继续拖动则会触发,我会检查拖动是否如此靠近我们需要的底部或顶部滚动。

这有效,但它有缺陷:

滚动时会回收视图,或者等效地,并非所有视图始终存在。拖动开始时,仅询问当前可见的视图是否要接受丢弃。随着列表向下滚动,添加了未被询问的新视图,并且它们不是有效的放置目标。解决方法是以下几行:

View child = mRecipeListView.getChildAt(mRecipeListView.getChildCount() - 1);
child.setVisibility(View.GONE);
child.setVisibility(View.VISIBLE);
向下滚动

这意味着获取了listView的最后一个子节点,其可见性更改为GONE并返回,这迫使它注册为有效的放置目标。用于向上滚动的模拟,但让孩子在索引0而不是最后一个。

出现了另一个问题,我找不到解决方案了:

1)我通过更改其背景颜色来突出显示用户正在拖动的项目。当用户现在向下滚动时,该项目的视图将被丢弃。当用户向上滚动时,视图将被回收,但现在它的视图与之前不同。后台将更改回默认值,并且保持对视图的引用也不起作用,因为相等检查将失败,因为回收的视图与原始视图不同。因此,我不知道如何保持此项目视图的背景更改。

2)滚动绑定到用户在有效放置目标的边界框内拖动时触发的事件。这迫使我保持​​视图可见用户正在拖动,因为我需要该视图的边界框来启动滚动事件,例如,顶部可见视图。我宁愿把它变成不可见的,但为此我必须在拖动事件约束之外滚动。

3)出于同样的原因:当用户将手指放在列表的底部并且有滚动空间时,只有在手指继续移动时才会保持滚动,否则不会触发新事件。

我试图对onTouchEvents作出反应,但似乎在拖动操作期间没有处理它们。

0 个答案:

没有答案