【发布时间】:2015-07-01 18:29:15
【问题描述】:
短版:
- 有没有办法让新创建的视图接收
DragEvents 已经运行的拖放操作?
有How to register a DragEvent while already inside one and have it listen in the current DragEvent?,但我真的想要一个更清洁的解决方案。
建议的 GONE->VISIBLE 解决方法要“正确”是相当复杂的,因为您需要确保仅在列表项变得可见时才使用它,而不是无条件地在所有当前列表视图项上使用。在这种情况下,hack 有点漏洞,没有更多的解决方法代码来让它正确。
加长版:
我有一个ListView。 ListView 的元素是包含可拖动符号(小框)的自定义视图,例如类似这样:
可以在ListView的项目之间拖动小盒子,就像将元素分类到盒子中一样。列表项上的拖动处理程序或多或少是微不足道的:
@Override
public boolean onDragEvent(DragEvent event)
{
if ((event.getLocalState() instanceof DragableSymbolView)) {
final DragableSymbolView draggedView = (DragableSymbolView) event.getLocalState();
if (draggedView.getTag() instanceof SymbolData) {
final SymbolData symbol = (SymbolData) draggedView.getTag();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DRAG_ENTERED:
setSelected(true);
return true;
case DragEvent.ACTION_DRAG_ENDED:
case DragEvent.ACTION_DRAG_EXITED:
setSelected(false);
return true;
case DragEvent.ACTION_DROP:
setSelected(false);
// [...] remove symbol from soruce box and add to current box
requestFocus();
break;
}
}
}
return super.onDragEvent(event);
}
将指针悬停在符号上并开始拖动(即,将其移动到一个小阈值之外)时开始拖动。
但是,现在屏幕大小可能不足以包含所有框,因此ListView 需要滚动。我发现我需要自己实现滚动,因为ListView 在拖动时不会自动滚动。
进来ListViewScrollingDragListener:
public class ListViewScrollingDragListener
implements View.OnDragListener {
private final ListView _listView;
public static final int DEFAULT_SCROLL_BUFFER_DIP = 96;
public static final int DEFAULT_SCROLL_DELTA_UP_DIP = 48;
public static final int DEFAULT_SCROLL_DELTA_DOWN_DIP = 48;
private int _scrollDeltaUp;
private int _scrollDeltaDown;
private boolean _doScroll = false;
private boolean _scrollActive = false;
private int _scrollDelta = 0;
private int _scrollDelay = 250;
private int _scrollInterval = 100;
private int _scrollBuffer;
private final Rect _visibleRect = new Rect();
private final Runnable _scrollHandler = new Runnable() {
@Override
public void run()
{
if (_doScroll && (_scrollDelta != 0) && _listView.canScrollVertically(_scrollDelta)) {
_scrollActive = true;
_listView.smoothScrollBy(_scrollDelta, _scrollInterval);
_listView.postDelayed(this, _scrollInterval);
} else {
_scrollActive = false;
}
}
};
public ListViewScrollingDragListener(final ListView listView, final boolean attach)
{
_scrollBuffer = UnitUtil.dipToPixels(listView, DEFAULT_SCROLL_BUFFER_DIP);
_scrollDeltaUp = -UnitUtil.dipToPixels(listView, DEFAULT_SCROLL_DELTA_UP_DIP);
_scrollDeltaDown = UnitUtil.dipToPixels(listView, DEFAULT_SCROLL_DELTA_DOWN_DIP);
_listView = listView;
if (attach) {
_listView.setOnDragListener(this);
}
}
public ListViewScrollingDragListener(final ListView listView)
{
this(listView, true);
}
protected void handleDragLocation(final float x, final float y)
{
_listView.getGlobalVisibleRect(_visibleRect);
if (_visibleRect.contains((int) x, (int) y)) {
if (y < _visibleRect.top + _scrollBuffer) {
_scrollDelta = _scrollDeltaUp;
_doScroll = true;
} else if (y > _visibleRect.bottom - _scrollBuffer) {
_scrollDelta = _scrollDeltaDown;
_doScroll = true;
} else {
_doScroll = false;
_scrollDelta = 0;
}
if ((_doScroll) && (!_scrollActive)) {
_scrollActive = true;
_listView.postDelayed(_scrollHandler, _scrollDelay);
}
}
}
public ListView getListView()
{
return _listView;
}
@Override
public boolean onDrag(View v, DragEvent event)
{
/* hide sequence controls during drag */
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_ENTERED:
_doScroll = true;
break;
case DragEvent.ACTION_DRAG_EXITED:
case DragEvent.ACTION_DRAG_ENDED:
case DragEvent.ACTION_DROP:
_doScroll = false;
break;
case DragEvent.ACTION_DRAG_LOCATION:
handleDragLocation(event.getX(), event.getY());
break;
}
return true;
}
}
当您在其可见区域的上边界或下边界附近拖动时,这基本上会滚动ListView。它并不完美,但已经足够了。
但是,有一个问题:
当列表滚动到以前不可见的元素时,该元素不会收到DragEvents。将符号拖到其上时,它不会被选中(突出显示),也不接受放置。
关于如何使“滚动”视图从已经活动的拖放操作中接收DragEvents 的任何想法?
【问题讨论】:
标签: android android-listview scroll drag-and-drop