我正在尝试在Android上实现一个ListView
子类,允许手动重新排序其内容。作为该过程的第一步,我将“长按”监听器附加到ListView
绘制的每个子视图,如:
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
//listen for long-click events as the trigger for reordering the list
child.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (! SortableListView.this.isSortEnabled()) {
return false;
}
//capture some state about the initial position of the list
//[...]
//note the view that we're moving around
dragView = view;
dragView.setBackgroundColor(Color.argb(128, 200, 200, 255));
dragView.setElevation(2.0f);
//disable the list's default scrolling behavior
SortableListView.this.requestDisallowInterceptTouchEvent(true);
return true;
}
});
//also add a general touch listener for when we're actually sorting things
child.setOnTouchListener(this);
return super.drawChild(canvas, child, drawingTime);
}
然后还有一个普通的'touch'事件监听器,用于在我们实际拖动某些东西时处理ListView
的更新:
@Override
public boolean onTouch(final View view, MotionEvent motionEvent) {
//XXX: (0,0) is at the top-left of the screen
if (dragView == null) {
//not dragging anything yet, just note the touch location for if/when we start
dragStartX = motionEvent.getRawX();
dragStartY = motionEvent.getRawY();
return false;
}
if (view != dragView) {
//not interested in this event
return false;
}
if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
dragCurrentX = motionEvent.getRawX();
dragCurrentY = motionEvent.getRawY();
//make the cell the user tapped follow their touch
dragView.animate().xBy(dragCurrentX - dragStartX).yBy(dragCurrentY - dragStartY).setDuration(0).start();
//now look at how far the view has moved, and reposition the displayed views if necessary (this is the broken part)
//[...]
return true;
}
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
//done, put the view back
dragView.setTranslationX(0);
dragView.setTranslationY(0);
dragView.setElevation(0.0f);
dragView = null;
//enable scrolling
this.requestDisallowInterceptTouchEvent(false);
return true;
}
return false;
}
问题在于,虽然拖动视图通常会起作用,但我还想在移动时将其“占位符”点向上/向下移动。也许最好用一些照片来说明这一点:
因此,当用户将其拖动到列表中时,目标是让“占位符”单元格跟随浮动蓝色单元格。我试图通过在浮动单元移动时操纵列表的子视图来完成此操作,但到目前为止没有任何工作。
我当前的代码(即“破碎的部分”)尝试这个:
int dragViewIndex = this.indexOfChild(dragView);
if (dragView.getTranslationY() > dragView.getHeight() && dragViewIndex < this.getChildCount() - 1) {
//move down 1 spot (towards bottom of list), reduce tY by height
this.detachViewFromParent(dragView);
this.attachViewToParent(dragView, dragViewIndex + 1, dragView.getLayoutParams());
dragView.setTranslationY(dragView.getTranslationY() - dragView.getHeight());
}
if (dragView.getTranslationY() < -1 * dragView.getHeight() && dragViewIndex > 0) {
//move up 1 spot (towards top of list), reduce tY by height
this.detachViewFromParent(dragView);
this.attachViewToParent(dragView, dragViewIndex - 1, dragView.getLayoutParams());
dragView.setTranslationY(dragView.getTranslationY() + dragView.getHeight());
}
但这似乎几乎没有任何结果(除了混淆列表之外;正如您在第三张图片中看到的那样,拖动的条目实际上在UI中显示两次)。
是否有一种正确/优雅的方式让空单元格跟踪列表中的内容?或者我是否需要查看更激烈的措施,例如翻译列表中的每个其他单元格以适应空白空间的位置?
答案 0 :(得分:0)
看来我在正确的轨道上有关于翻译列表中其他单元格的想法。这段代码符合我的要求:
if (dragView.getTranslationY() - dragView.getHeight() * numShifts > dragView.getHeight() && dragViewIndex < this.getChildCount() - 1) {
//move down 1 spot (towards bottom of list)
View displacedView = this.getChildAt(dragViewIndex + 1);
if (displacedView.getTranslationY() != 0) {
displacedView = this.getChildAt(dragViewIndex);
displacedView.animate().translationY(0).setDuration(100).start();
}
else {
displacedView.animate().yBy(-1 * view.getHeight()).setDuration(100).start();
}
dragViewIndex++;
numShifts++;
}
else if (dragView.getTranslationY() - dragView.getHeight() * numShifts < -1 * dragView.getHeight() && dragViewIndex > 0) {
//move up 1 spot (towards top of list)
View displacedView = this.getChildAt(dragViewIndex - 1);
if (displacedView.getTranslationY() != 0) {
displacedView = this.getChildAt(dragViewIndex);
displacedView.animate().translationY(0).setDuration(100).start();
}
else {
displacedView.animate().yBy(view.getHeight()).setDuration(100).start();
}
dragViewIndex--;
numShifts--;
}
可能会被清理一下。但基本上你可以看到细胞被拖动了多远,每次它上下移动一个完整的增量(根据它的高度),你可以根据需要上下移动细胞。这会创建“占位符”单元格在列表中移动的外观。
请注意,此代码仅在列表中的每个项目具有相同高度时才有效。这对我的用例来说已经足够了,但不适用于每个用例。