Java 在ListView中操作显示的视图

Java 在ListView中操作显示的视图,java,android,listview,animation,Java,Android,Listview,Animation,我试图在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

我试图在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);
}
此外,还有一个通用的“触摸”事件侦听器,用于在我们实际拖动某些内容时处理对
列表视图的更新:

@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());
}
int-dragViewIndex=this.indexOfChild(dragView);
if(dragView.getTranslationY()>dragView.getHeight()&&dragViewWindex0){
//向上移动1点(朝向列表顶部),减少高度
此.detachViewFromParent(dragView);
this.attachViewToParent(dragView,dragView-windex-1,dragView.getLayoutParams());
dragView.setTranslationY(dragView.getTranslationY()+dragView.getHeight());
}
但这似乎什么也没有完成(除了混淆列表;正如您在第三张图片中看到的,被拖动的条目实际上在UI中出现了两次)


有没有合适/优雅的方法让空单元格跟随列表中的内容?或者我需要考虑更激烈的措施,比如可能翻译列表中的其他单元格以适应空白的位置?

看来我翻译列表中其他单元格的想法是正确的。此代码符合我的要求:

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--;
}
if(dragView.getTranslationY()-dragView.getHeight()*numshift>dragView.getHeight()&&dragViewWindex0){
//向上移动1个位置(朝向列表顶部)
View-displacedView=this.getChildAt(dragViewIndex-1);
if(displacedView.getTranslationY()!=0){
displacedView=this.getChildAt(dragViewIndex);
displacedView.animate().translationY(0).setDuration(100).start();
}
否则{
displacedView.animate().yBy(view.getHeight()).setDuration(100.start();
}
dragViewIndex--;
数字移位--;
}
也许可以清理一下。但基本上,您可以观察单元格被拖动的距离,每次它向上/向下移动一个完整的增量(基于其高度),您可以根据需要向上/向下移动它下面的单元格。这将创建“占位符”单元格在列表中移动的外观

请注意,此代码仅在列表中的每个项目都具有相同高度时有效。这对于我的用例来说已经足够好了,但不是每一个用例