java drag and drop,Drag and Drop

本文深入介绍了Android中的拖放框架,该框架允许用户通过手势将数据从一个视图移动到另一个视图。在拖放过程中,系统会发送一系列事件给注册了监听器的View,监听器可以根据事件类型决定是否接受数据。拖放操作分为开始、持续、放下和结束四个阶段。在拖放阴影被放下时,系统会将数据发送给接受它的View。开发者可以通过实现拖放事件监听器或回调方法来定制拖放行为,如改变UI、混合颜色等。
摘要由CSDN通过智能技术生成

使用 Android 的拖放框架,应用程序可以允许用户通过拖放手势将数据从一个视图移动到另一个视图。这个框架中包括拖拽事件的类、监听器、其他一些辅助的类。

尽管这个框架是被设计用来移动数据的,但是我们也可一用它来改变 UI 显示。比如当将一个颜色图像拖放到另一个颜色图标上时,可以让这两种颜色混合起来。但是这篇文章主要介绍的是数据的拖动。

Overview

当用户作出我们定义的拖放手势时,就开始了拖放操作。应用程序会告诉系统拖放操作开始,系统回调应用程序来获取拖动的数据。当用户用手指拖动当前layout上的图像(拖动阴影)时,系统会把拖动事件发送给那些拖动事件监听器,以及在当前layout中

Note: 为了简便,下面将处理拖动事件的方法都叫做"拖动事件监听器"尽管它可能是一个回调方法。

当开始拖动时,要将需要移动的数据以及描述这些数据的元数据都传递给系统。在拖动过程中,系统会将拖动事件发送给当前 layout 中的每一个 View 的拖动事件监听器或者回调方法。监听器或者回调方法可以使用元数据来决定是否想要接受放下来的数据。如果用户将数据拖到某一个 View 上放下,这个 View 监听器或者回调方法已经告诉系统它想要接受放下的数据,那么系统将会把拖动事件中的数据发送给监听器或者回调方法。

在程序中,通过调用

你可以调用当前 layout 中任何一个 View 的

当你调用了

The drag/drop process

拖放过程有4个基本步骤:

Started

应用程序调用

系统首先会回调应用程序来绘制拖动阴影,它将会作为拖动过程中的阴影来显示。

接下来系统将会向layout中的所有 View 对象发送一个类型为 true.这会向系统注册监听器,只有注册过的监听器才能收到连续的拖动事件。这个时候,可以改变 View 对象的外观来表示监听器可以接受放下事件。

如果拖动事件监听器返回了 false,那这个 View 将不会再收到系统发送的拖动事件了,除非等系统发出类型为 false,监听器告诉系统它对这次拖动操作不感兴趣,并且也不想接收拖动的数据。

Continuing

用户保持拖动的动作,当拖动阴影与 View 的边界接触时,系统会发送一个或多个拖动事件给 View 对象的监听器(前提时这个View注册过监听器)。监听器可以去改变 View 的外观来响应这个事件。举个例子,当拖动阴影与 View 的边界接触时(类型为

Dropped

用户在一个 View 的边界内松开拖动阴影,这个 View 便可以接受拖动数据。系统会发送一个类型为 true.

发生这一步需要两个条件,首先用户必须要在 View 的边界内放下拖动阴影,其次这个 View 已经注册了接受这个事件的监听器。除此之外的其他情况,都不会有

Ended

当用户松开阴影后,并且系统已经发出了(如果需要)

The drag event listener and callback method

一个 View 通过继承于

你应该在大多数情况下使用监听器。当设计 UI 时,通常不会继承 View 类,但是如果想要使用回调方法就必须继承 View 类,因为得复写方法。相比而言,可以实现一个监听器并且将它设给多个不同的 View 对象。你也可以将它实现为匿名内部类,通过

你可以为一个 View 设置监听器和回调方法,这种情况下,系统会首先调用监听器。只有在监听器返回 false 时,系统才会调用回调方法。

Drag events

系统发出的拖动事件都是

要获取事件类型,监听器可以调用事件的 table 1中.

table 2中。表中海详细阐述了可以在 Designing a Drag and Drop Operation 中使用的事件。

Table 1. 拖动事件类型

getAction() value

Meaning

当调用了

当拖动阴影与 View 的边界发生接触时,监听器会收到这个事件。这是拖动阴影进入 View 的边界时监听器收到的第一个事件。如果监听器想要继续接受此次拖动事件,必须向系统返回 true.

当监听器接收到

当用户在 View 的边界内放下拖动阴影时,监听器就会收到这个事件。只有那些收到 true 的监听器才会收到这个事件。如果用户在一个没有注册监听器的 View 上释放拖动阴影,或者不在当前layout上释放拖动阴影,这个事件将不会发出。

如果监听器成功处理了放下事件,应该返回 true,否则应该返回 false.

View 的监听器将会在系统结束拖动操作时收到这个类型的事件。这个事件的发出不依赖 false.

Table 2. Valid DragEvent data by action type

如果一个方法在特定的事件中不能得到有效的返回值,此方法会返回 null 或0,视结果类型而定。

The drag shadow

在拖放过程中,系统显示一个用户拖动的图像。在拖动数据时,这个图像就代表着数据,对其它操作来说,它代表着拖动的东西。

这个图像就是拖动阴影。你可以通过申明

这个构造器接收你程序中的任何一个 View 对象,这个构造器会把这个 View 存储在

如果选择的是这个构造器,你不必继承

如果你使用的是这个构造器,

在调用了 dimensions

一个

touch_point

一个

系统调用完 Canvas 对象上。

为提高性能,你应该尽可能地让拖动阴影的尺寸很小。对单个的对象,可以使用一个 icon,对多个选择,应该让 icon 重叠显示,而不是将它们整个显示在屏幕上。

Designing a Drag and Drop Operation

这一节讲述怎样一步步开始拖动操作,怎样响应拖动过程中的事件。怎样响应一个放下事件,以及怎样结束拖放操作.

Starting a drag

用户收到拖动手势时,就开是拖动操作,通常是长按一个 View.在事件响应中,应该这么做:

必须要创建用来移动数据的 null 来替代这个对象。

举个例子,下面的代码展示了在长按 ImageView 时,去创建一个包含 ImageView 的 tag和 label 数据的 ClipData 对象。接下来的代码将展示如何去复写

// Create a string for the ImageView label

private static final String IMAGEVIEW_TAG = "icon bitmap"

// Creates a new ImageView

ImageView imageView = new ImageView(this);

// Sets the bitmap for the ImageView from an icon bit map (defined elsewhere)

imageView.setImageBitmap(mIconBitmap);

// Sets the tag

imageView.setTag(IMAGEVIEW_TAG);

...

// Sets a long click listener for the ImageView using an anonymous listener object that

// implements the OnLongClickListener interface

imageView.setOnLongClickListener(new View.OnLongClickListener() {

// Defines the one method for the interface, which is called when the View is long-clicked

public boolean onLongClick(View v) {

// Create a new ClipData.

// This is done in two steps to provide clarity. The convenience method

// ClipData.newPlainText() can create a plain text ClipData in one step.

// Create a new ClipData.Item from the ImageView object's tag

ClipData.Item item = new ClipData.Item(v.getTag());

// Create a new ClipData using the tag as a label, the plain text MIME type, and

// the already-created item. This will create a new ClipDescription object within the

// ClipData, and set its MIME type entry to "text/plain"

ClipData dragData = new ClipData(v.getTag(),ClipData.MIMETYPE_TEXT_PLAIN,item);

// Instantiates the drag shadow builder.

View.DragShadowBuilder myShadow = new MyDragShadowBuilder(imageView);

// Starts the drag

v.startDrag(dragData, // the data to be dragged

myShadow, // the drag shadow builder

null, // no need to use local data

0 // flags (not currently used, set to 0)

);

}

}

下面的代码定义了 myDragShadowBuilder,它在拖动 TextView 时创建一个灰色的矩形拖动阴影:

private static class MyDragShadowBuilder extends View.DragShadowBuilder {

// The drag shadow image, defined as a drawable thing

private static Drawable shadow;

// Defines the constructor for myDragShadowBuilder

public MyDragShadowBuilder(View v) {

// Stores the View parameter passed to myDragShadowBuilder.

super(v);

// Creates a draggable image that will fill the Canvas provided by the system.

shadow = new ColorDrawable(Color.LTGRAY);

}

// Defines a callback that sends the drag shadow dimensions and touch point back to the

// system.

@Override

public void onProvideShadowMetrics (Point size, Point touch)

// Defines local variables

private int width, height;

// Sets the width of the shadow to half the width of the original View

width = getView().getWidth() / 2;

// Sets the height of the shadow to half the height of the original View

height = getView().getHeight() / 2;

// The drag shadow is a ColorDrawable. This sets its dimensions to be the same as the

// Canvas that the system will provide. As a result, the drag shadow will fill the

// Canvas.

shadow.setBounds(0, 0, width, height);

// Sets the size parameter's width and height values. These get back to the system

// through the size parameter.

size.set(width, height);

// Sets the touch point's position to be in the middle of the drag shadow

touch.set(width / 2, height / 2);

}

// Defines a callback that draws the drag shadow in a Canvas that the system constructs

// from the dimensions passed in onProvideShadowMetrics().

@Override

public void onDrawShadow(Canvas canvas) {

// Draws the ColorDrawable in the Canvas passed in from the system.

shadow.draw(canvas);

}

}

Note: 要记住不一定非要去继承

Responding to a drag start

在拖动过程中,系统会给当前layout中所有View的事件监听器分发拖动事件。监听器需要调用

为了响应类型为

调用

如果拖动操作没有移动数据,那么就可以省略这一步。

如果监听器能够接收放下操作,那应该返回 true,这将告诉系统继续向监听器发送本次拖动事件。如果不能接受要放下操作,应该返回 false,系统在这之后,只会像监听器发送

Handling events during the drag

在拖动过程中,只有那些在接收到 true 的监听器才会收到拖动事件。监听器能否收到这中类型的事件与拖动阴影的位置和监听器所属的 View 的可见性有关。

在拖动过程中,监听器会跟觉拖动事件来改变 View 的外观.

在拖动过程中,监听器调用 code>getAction() 方法可以得到下面三种返回值:

监听器不需要对下面的事件类型有返回值,就算有返回值,也会被系统忽略。下面是在响应这些事件时的一些建议:

一个

响应

Responding to a drop

当用户在一个 View 上松开拖动阴影,并且这个 View 的监听器在拖动开始时已经告诉系统可以接受拖动的数据,系统将会分发

调用

返回 true 表示数据成功放下,返回 false 则表示数据没有成功放下。返回的结果可以通过

对于

系统允许用户在不接受拖动事件的 View 上释放拖动阴影,也允许用户在空白的地方释放拖动阴影,甚至在应用程序范围之外释放。在这些情况下,系统不会向发出

Responding to a drag end

当用户释放拖动阴影后,系统会向应用同程中所有的监听器发送

每一个监听器应该完成下面的工作:

如果 View 的外观在拖动过程中做了改变,那么此时应该变回原来的样子。这可以让用户看到拖放操作的结束。

监听器此时可以选择性的调用 true,那么 true,其他情况下 false,不管系统有没有发出过

监听器应该返回 true 给系统.

Responding to drag events: an example

所有的拖动事件都可一被监听器或者拖动事件方法收到,下面的带面通过监听器来接受拖动事件:

// Creates a new drag event listener

mDragListen = new myDragEventListener();

View imageView = new ImageView(this);

// Sets the drag event listener for the View

imageView.setOnDragListener(mDragListen);

...

protected class myDragEventListener implements View.OnDragEventListener {

// This is the method that the system calls when it dispatches a drag event to the

// listener.

public boolean onDrag(View v, DragEvent event) {

// Defines a variable to store the action type for the incoming event

final int action = event.getAction();

// Handles each of the expected events

switch(action) {

case DragEvent.ACTION_DRAG_STARTED:

// Determines if this View can accept the dragged data

if (event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {

// As an example of what your application might do,

// applies a blue color tint to the View to indicate that it can accept

// data.

v.setColorFilter(Color.BLUE);

// Invalidate the view to force a redraw in the new tint

v.invalidate();

// returns true to indicate that the View can accept the dragged data.

return(true);

} else {

// Returns false. During the current drag and drop operation, this View will

// not receive events again until ACTION_DRAG_ENDED is sent.

return(false);

}

break;

case DragEvent.ACTION_DRAG_ENTERED: {

// Applies a green tint to the View. Return true; the return value is ignored.

v.setColorFilter(Color.GREEN);

// Invalidate the view to force a redraw in the new tint

v.invalidate();

return(true);

break;

case DragEvent.ACTION_DRAG_LOCATION:

// Ignore the event

return(true);

break;

case DragEvent.ACTION_DRAG_EXITED:

// Re-sets the color tint to blue. Returns true; the return value is ignored.

v.setColorFilter(Color.BLUE);

// Invalidate the view to force a redraw in the new tint

v.invalidate();

return(true);

break;

case DragEvent.ACTION_DROP:

// Gets the item containing the dragged data

ClipData.Item item = event.getClipData().getItemAt(0);

// Gets the text data from the item.

dragData = item.getText();

// Displays a message containing the dragged data.

Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG);

// Turns off any color tints

v.clearColorFilter();

// Invalidates the view to force a redraw

v.invalidate();

// Returns true. DragEvent.getResult() will return true.

return(true);

break;

case DragEvent.ACTION_DRAG_ENDED:

// Turns off any color tinting

v.clearColorFilter();

// Invalidates the view to force a redraw

v.invalidate();

// Does a getResult(), and displays what happened.

if (event.getResult()) {

Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG);

} else {

Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG);

};

// returns true; the value is ignored.

return(true);

break;

// An unknown action type was received.

default:

Log.e("DragDrop Example","Unknown action type received by OnDragListener.");

break;

};

};

};

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值