我有一个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
作出反应,但似乎在拖动操作期间没有处理它们。