Android拖放教程

这篇文章将介绍如何在Android应用程序中实现拖放。

(我目前使用的是sdk的4.0版,但我最初使用3.1版编写了该系列的代码。)

为什么要使用拖放

当我开始处理涉及在棋盘周围移动棋子的Android应用程序时,出于以下两个原因,我选择使用拖放功能:

  1. 我觉得拖放将尽可能接近将棋子在板上移动的体验。
  2. 通过拖放,通过将棋子放在单个对象(在本例中为棋盘上的正方形)上,而不是跟踪棋子的x,y坐标,可以更有效地确定有效棋步。 我将在本系列的最后一部分中解释有关如何实现此功能的更多信息。

我的拖放目标

在实现拖放方面,在棋盘上移动棋子方面,我有3个具体目标。

  1. 当用户按下并开始拖动时,棋子将替换为原版的轻得多的版本,从而很明显它已被移动。
  2. 我想限制可拖动棋子的区域,更具体地说,我不想让玩家将棋子从棋盘上拖出
  3. 如果玩家试图放下游戏棋子而导致非法移动,我希望游戏棋子“弹回”到其原始位置。

在这里,我将介绍我拖放应用程序的第一个目标。

在开始拖动时更改ImageView

当我开始工作时,我意识到拖放功能并不能立即支持我想要的功能,但是可以肯定的是,只需少量的工作,api中的功能就足以满足我的需求。 当用户按下棋子(即ImageView)以开始拖动时,我将采取以下步骤:

  1. 创建一个DragShadowBuilder对象。
  2. 调用startDrag方法。
  3. 通过调用setVisibility并传​​递View.INVISIBLE来隐藏原始的ImageView(象棋棋子),仅使DragShadowBuilder对象可见,从而清楚地指示拖动已开始。

上面的步骤全部在ImageView的OnTouchListner对象中的已实现onTouch方法中完成。 这是代码:

@Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            ClipData clipData = ClipData.newPlainText("", "");
            View.DragShadowBuilder dsb = new View.DragShadowBuilder(view);
            view.startDrag(clipData, dsb, view, 0);
            view.setVisibility(View.INVISIBLE);
            return true;
        } else {
            return false;
        }
    }

更改了开始拖动时的棋子图像!

到目前为止,我已经介绍了如何隐藏ImageView并仅在拖动开始时显示了DragShadowBuilder对象。 现在,我将集中精力限制拖动区域。

试图限制拖动区域

由于我的应用程序涉及在棋盘上移动棋子,因此我想将拖动区域限制在游戏板本身上。 我的动机是在拖动开始时将ImageView隐藏。 如果ImageView从板上掉下来,它将再也不会出现。 那会使我的应用程序处于不一致状态。 因此,我花了一些时间浏览Android api,并仔细研究了如何限制拖动区域。 我什么都没想到。 然后我退后一步,以为我要解决什么问题? 用户是否将ImageView拖到板上? 不,真正的问题是放置动作从未处理过,所以我再也没有机会使ImageView再次可见。 因此,我将问题重新定义为确定放置有效期的时间。

确定有效丢弃

为了弄清楚如何确定有效的放置,我返回了Android Developer文档。 我在处理拖曳结束事件方面做得很好。 这是我发现的要点:

  • 拖动结束后,将ACTION_DRAG_ENDED事件发送到所有DragListener。
  • DragListener可以通过调用DragEvent的getResult方法来确定有关拖动操作的更多信息。
  • 如果DragListener从ACTION_DROP事件返回true,则getResult调用将返回true,否则返回false。

现在我很清楚,当/如果用户将棋子拖放到非预期区域时,我可以做什么。 对于onDrag方法中处理的任何事件,我的DragListener类都已经返回true。 因此,从getResult返回的false值表示该掉落发生在游戏板上某处。 我现在需要做的是:

  1. 发生ACTION_DRAG_ENDED事件时,请调用getResult方法
  2. 如果getResult返回false,请立即将ImageView的可见性(在拖动开始时使用)重新设置为visible。

这是代码,相关行突出显示:

@Override
    public boolean onDrag(View view, DragEvent dragEvent) {
        int dragAction = dragEvent.getAction();
        View dragView = (View) dragEvent.getLocalState();
        if (dragAction == DragEvent.ACTION_DRAG_EXITED) {
            containsDragable = false;
        } else if (dragAction == DragEvent.ACTION_DRAG_ENTERED) {
            containsDragable = true;
        } else if (dragAction == DragEvent.ACTION_DRAG_ENDED) {
            if (dropEventNotHandled(dragEvent)) {
                dragView.setVisibility(View.VISIBLE);
            }
        } else if (dragAction == DragEvent.ACTION_DROP && containsDragable) {
            checkForValidMove((ChessBoardSquareLayoutView) view, dragView);
            dragView.setVisibility(View.VISIBLE);
        }
        return true;
    }

    private boolean dropEventNotHandled(DragEvent dragEvent) {
        return !dragEvent.getResult();
    }

现在,用户可以将ImageView拖放到任何地方,并且游戏不会以不一致的状态结束。 我的第二个目标实现了。

最后一部分涵盖由于有效移动而移动游戏作品,或者在进行无效移动时使游戏作品“跳回”其原始位置。

应用背景信息

我的应用程序上的一些背景信息可能对这篇文章有所帮助。 游戏涉及在棋盘上移动一个棋子(一个骑士)。 棋盘是一个TableLayout,每个正方形都是LinearLayout的子类,并具有OnDragListener设置。 此外,每个OnDragListener都有对“中介”对象的引用,该对象是:

  1. 处理对象之间的通信。
  2. 跟踪当前方块(最后一次有效移动的着陆方块)。

确定有效移动

当用户开始拖动ImageView并经过给定的正方形时,可以执行以下操作:

  • 使用ACTION_DRAG_ENTERED事件将实例变量“ containsDraggable”设置为true。
  • 使用ACTION_DRAG_EXITED事件将“ containsDraggable”设置为false。
  • 当在一个正方形上发生ACTION_DROP事件时,通过从“当前”正方形检查所有可能的有效移动(预先计算),询问调解员尝试的移动是否有效。

以下是突出显示相关部分的代码:

@Override
    public boolean onDrag(View view, DragEvent dragEvent) {
        int dragAction = dragEvent.getAction();
        View dragView = (View) dragEvent.getLocalState();
        if (dragAction == DragEvent.ACTION_DRAG_EXITED) {
            containsDragable = false;
        } else if (dragAction == DragEvent.ACTION_DRAG_ENTERED) {
            containsDragable = true;
        } else if (dragAction == DragEvent.ACTION_DRAG_ENDED) {
            if (dropEventNotHandled(dragEvent)) {
                dragView.setVisibility(View.VISIBLE);
            }
        } else if (dragAction == DragEvent.ACTION_DROP && containsDragable) {
            checkForValidMove((ChessBoardSquareLayoutView) view, dragView);
            dragView.setVisibility(View.VISIBLE);
        }
        return true;
    }

从上面可以看到,无论移动是否有效,ImageView都可见。 通过在放下图像后立即使ImageView可见,可以实现我无缝移动或“跳回”其原始位置的目标。

移动ImageView

之前,我提到每个正方形都是LayoutView的子类。 这样做是为了轻松将ImageView从一个正方形移到另一个正方形。 这是来自checkForValidMove方法(上面的代码示例中的第14行)的详细信息,这些信息显示了如何完成ImageView的移动。

private void checkForValidMove(ChessBoardSquareLayoutView view, View dragView) {
        if (mediator.isValidMove(view)) {
            ViewGroup owner = (ViewGroup) dragView.getParent();
            owner.removeView(dragView);
            view.addView(dragView);
            view.setGravity(Gravity.CENTER);
            view.showAsLanded();
            mediator.handleMove(view);
        }
    }

我希望读者会发现本文对他们自己的Android开发工作有所帮助。

参考:来自我们JCG合作伙伴 Bill Bejeckat的《 随机编码想法》博客中的Android拖放(第1部分)Android拖放(第2部分)Android拖放(第3部分)

相关文章 :


翻译自: https://www.javacodegeeks.com/2011/12/android-drag-and-drop-tutorial.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值