首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >操纵ListView中显示的视图

操纵ListView中显示的视图
EN

Stack Overflow用户
提问于 2017-03-21 16:19:28
回答 1查看 28关注 0票数 0

我试图在Android上实现一个ListView子类,该子类允许手动重新排序其内容。作为该过程的第一步,我将向ListView绘制的每个子视图附加一个“长击”侦听器,例如:

代码语言:javascript
复制
@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);
}

然后还有一个通用的“触摸”事件侦听器,一旦我们实际拖动一些东西,就可以处理对ListView的更新:

代码语言:javascript
复制
@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;
}

问题是,虽然拖曳视图通常有效,但我也想在它移动时将它的“占位符”位置上下移动。也许最好用一些照片来说明这一点:

初始状态

在开始拖动之后

拖动一点后的

因此,目标是让“占位符”单元格跟随浮动的蓝色单元格,用户将其拖过列表。当浮动单元格移动时,我试图通过操作列表的子视图来实现这一点,但是到目前为止,没有任何东西工作。

我当前用于尝试此操作的代码(即“破损部分”)是:

代码语言:javascript
复制
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中拖动的条目实际上出现了两次)。

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

EN

回答 1

Stack Overflow用户

发布于 2017-03-22 02:22:09

似乎我对翻译列表中其他单元格的想法是正确的。这个代码实现了我想要的结果:

代码语言:javascript
复制
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--;
}

可能会被清理一下。但是基本上,您可以观察单元格被拖到多远,每次它向上/向下移动一个完整的增量(根据它的高度),您就会根据情况上下移动它下面的单元格。这将创建在列表中移动的“占位符”单元格的外观。

注意,只有当列表中的每个项目都具有相同的高度()时,此代码才能工作。这对我的用例来说已经足够好了,但并不适合每个用例。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42932737

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档