设计拖放操作

本节主要内容如下:

1.  如何开始拖拽;

2.  在拖拽期间如何响应事件;

3.  如何响应落下事件;

4.  如何结束拖放操作。

开始拖拽

用户使用一个拖拽手势开始拖拽,通常是在View对象上长按。在响应中,应该做下列事情:

1.  必要时,给要移动的数据创建一个ClipData和ClipData.Item对象,作为ClipData对象的一部分,在ClipData对象内部的ClipDescription对象中保存了元数据。因为拖放操作不代表数据的移动,因此可以使用null来代替实际的对象。

例如,以下代码段显示了如何在ImageView对象的长按事件上创建一个包含ImageView对象标签的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)

);

}

}

2. 以下代码段定义了一个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);

}

}

注意:不必扩展View.DragShadowBuilder类,因为构造器View.DragShadowBuilder(View)会创建一个默认的跟传递给它的View对象相同尺寸的拖拽影子,而且触点在拖拽影子的中心。

对拖拽开始的响应

在拖拽操作期间,系统会分发拖拽事件给当前布局中View对象的拖拽事件监听器。监听器应该通过调用getAction()方法对获得的操作类型做出反应。在拖拽开始时,这个方法返回ACTION_DRAG_STARTED.

在对ACTION_DRAG_STARTED操作类型做出的响应中,监听器应该做下列事情:

1.  调用getClipDescription()方法来获得ClipDescription对象,使用ClipDescription对象中的MIME类型方法来判断监听器是否能够接收被拖拽的数据。

如果拖拽操作不代表要移动的数据,这个判断就不是必须的了。

2.  如果监听器能够接受落下事件,它应该返回true。这样就告诉系统可以继续给这个监听器发送拖拽事件。如果不能够接收落下事件,它应该返回false,系统就不再会给这个监听器发送拖拽事件了。

要注意的是针对ACTION_DRAG_STARTED事件,下列DragEvent对象方法不能获取有效的数据:getClipData()、getX()、getY()和getResult()。

在拖拽期间处理事件

在拖拽期间,在响应ACTION_DARG_STARTED拖拽事件中返回true的监听器会继续接收拖拽事件。这种类型的拖拽监听器会依赖拖拽期间拖拽影子的位置和监听器的View对象的可见性来接收拖拽事件。

在拖拽期间,监听器主要使用拖拽事件来判断是否应该改变View对象的外观。

拖拽期间,getAction方法会返回下列三个值之一:

1. ACTION_DRAG_ENTERED:当触点(触屏上手指下方的点)进入监听器View对象的边框时,View对象的拖拽监听器就会收到这个事件。

2. ACTION_DRAG_LOCATION:一旦拖拽监听器收到一个ACTION_DRAG_ENTERED事件,并且在收到ACTION_DRAG_EXITED事件之前,每次移动触点时都会收到一个新的ACTION_DRAG_LOCATION事件。getX和getY()方法会返回触点的X和Y轴坐标。

3. ACTION_DRAG_EXITED:在拖拽影子离开监听器View对象的边框之后,这个事件会发送给之前收到ACTION_DRAG_ENTERED事件的那个监听器。

监听器不需要对这些操作类型都做出反应,如果监听器给系统返回了一个值,它就会被忽略。以下是响应这些操作类型的一些指南:

1.  在对ACTION_DRAG_ENTERED或ACTION_DRAG_LOCATION事件的响应中,监听器能够改变View对象的外观来指示View对象能够接受放下事件。

2. ACTION_DRAG_LOCATION事件包含了对getX()和getY()方法有效的数据,这两个方法的返回值对应了触点的位置。监听器可以使用这个信息来修改触点所在的View对象的外观,也能使用这个信息来判断用户拖放阴影的准确位置。

3. 在对ACTION_DRAG_EXITED事件的响应中,监听器应该重设在响应ACTION_DRAG_ENTERED或ACTION_DRAG_LOCATION事件对外观的任何改变。这个事件指示拖放对象已经离开准备放下的目标。

响应放下事件

当用户在应用中的一个View对象上释放了拖拽影子,并且这个View对象是之前报告的能够接收被拖拽内容的那个View对象,系统就会给这个View对象发送一个ACTION_DROP类型的拖拽事件。监听器应该做下列事情:

1.  调用getClipData()方法获得ClipData对象,这个对象在调用startDrag()方法时被初始化并保存在拖拽监听器中。如果拖放操作不移动数据,那么就不需要做这件事;

2.  返回true,指示放下事件被成功处理,否则返回false。对于ACTION_DRAG_ENDED事件,这个返回值就是通过getResult()方法返回的值。

要注意的是,如果系统不发送ACTION_DROP事件,针对对ACTION_DRAG_ENDED事件的getResult()方法调用的返回值是false。

系统允许用户在监听器不接收拖放事件的View对象之上释放拖拽影子,也允许用户在应用程序UI的空白区域或应用程序以外的区域释放拖拽影子,这样系统就不会发出ACTION_DROP类型的事件,直接会发出一个ACTION_DRAG_ENDED事件。

响应拖拽结束事件

用户释放了拖拽影子后,系统会立即给应用程序中所有的拖拽事件监听器发送ACTION_DRAG_ENDED类型的拖拽事件,指示拖拽操作结束了。

每个监听器都应该做下列事情:

1.  如果监听器在操作期间改变了View对象的外观,那么应该把View对象重设为默认的外观。这是对用户可见的操作结束的指示;

2.  监听器能够可选的调用getResult()方法来查找更多的相关操作。如果在响应ACTION_DROP类型的事件中监听器返回了true,那么getResult()方法也会返回true。在其他的情况中,getResult()方法会返回false,包括系统没有发出ACTION_DROP事件的情况;

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

响应拖拽事件的一个例子:

所有的拖拽事件都会被拖拽事件的回调方法或监听器接收。以下代码片段是一个简单的在监听器中对拖拽事件作出反应的示例。// 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;

};

};

};

android交互功能,Android 用户界面交互---拖放(OnDragListener)相关推荐

  1. android远程打电话,Android打电话功能 Android实战教程第三篇之简单实现拨打电话功能...

    想了解Android实战教程第三篇之简单实现拨打电话功能的相关内容吗,杨道龙在本文为您仔细讲解Android打电话功能的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Android拨打电话 ...

  2. android侧边栏功能,Android实现滑动侧边栏

    在Android应用开发中,滑动侧边栏经常使用,今天我也试着自己进行了一个简单的实践,虽然功能还不是很强大,但是可以保留下来为以后的开发使用,有需要时在进行简单的修改.实现一个滑动侧边栏思路也很简单: ...

  3. android倒计时功能,android实现倒计时功能(开始、暂停、0秒结束)

    本文实例为大家分享了android实现倒计时功能的具体代码,供大家参考,具体内容如下 [思路]:通过 timer 执行周期延时的任务,handler 中将计时信息更新,并在计时结束时结束 timer ...

  4. android倒计时功能,Android 实现列表倒计时功能

    Android 实现列表倒计时功能 发布时间:2020-08-21 21:47:11 来源:脚本之家 阅读:147 作者:Choi晨 单个计时器,然后遍历数据 刷新条目: 两种实现方式:1.Handl ...

  5. android Textview 功能,Android:TextView的常用功能

    android:autoText如果设置,将自动执行输入值的拼写纠正.此处无效果,在显示输入法并输入的时候起作用 android:bufferType指定getText()方式取得的文本类别.选项ed ...

  6. android提醒功能,android service实现循环定时提醒功能

    人每天都要喝8杯水才能保持健康,于是苦逼的程序员总是一遍代码就忘了时间,于是我突发奇想能不能开发一个apk能够实现固定的间隔时间定时提醒我要喝水了呢? apk基本功能: 1)能够设置间隔时间 2)在a ...

  7. Android好评功能,Android自定义View实现五星好评效果

    本文实例为大家分享了Android实现五星好评效果的具体代码,供大家参考,具体内容如下 这个效果想必大家都非常熟悉,那么Android如何自定义实现这种效果呢? 首先自定义属性: 下面看看具体实现: ...

  8. android+注销功能,Android app注销账号和完全退出简单实现

    写这篇文章的目的主要是用来记录一下这块的知识,同时也能够帮助对这块不太熟悉的朋友.      app账号的注销以及完全退出销毁整个app可以说是开发app必备的功能,虽然知识不是很深但是对一些接触an ...

  9. android菜单功能,Android“设置”菜单

    本部分介绍了实现和自定义 Android"设置"菜单可以使用的选项. 设置主屏幕 在 Android 7.0 及更高版本中,"设置主屏幕"页面因增添了建议的设置 ...

最新文章

  1. php.ini网站空白,php配置问题:拷贝php.ini后,测试页面无法显示(显示空白)
  2. 有关javabean的说法不正确的是_【以案说法】从业人员劳动保护用品费不能省!否则得不偿失.........
  3. java windows so文件_windows下编译使用NDK,调用SO文件 | 学步园
  4. JSP之内置对象、作用域
  5. apiclod 上传图片_Apicloud——关于上传图片、视频(二)
  6. 哈萨比斯首次解读AlphaZero竟被当场diss,他起身当面回击说…
  7. 检测React组件外部的点击
  8. mysql中设置字符,MySQL 修改默认字符集
  9. [android]亲自破解Flappy Bird(去广告+永生)
  10. html下拉菜单的某个值被选定,使用JavaScript在下拉列表中获取选定的值?
  11. [J2SE]JTree使用DefaultTreeModel,对节点进行增删、拖拽和展开操作,以及跨平台文件拖拽的方法详细介绍
  12. 利用FME(myfme)将MAPGIS格式的土地处用现状图完美转换为CAD
  13. 卡塔尔世界杯出现了半自动越位识别技术、Feelix Palm、动作轨迹捕捉等黑科技,一起来看看吧。
  14. 以一元及二元函数为例,通过多项式的函数图像观察其拟合性能;以及对用多项式作目标函数进行机器学习时的一些理解。
  15. epub格式电子书制作工具——ep…
  16. 数据结构——树 | 孩子双亲数组表示法
  17. 脑芯编 | 窥脑究竟,结网造芯(三)
  18. 二十世纪最伟大的十大算法
  19. oracle 重建控制文件 恢复数据库
  20. Linux环境下安装TASSEL_5_standalone

热门文章

  1. 使用Spring 3引导Web应用程序
  2. 使用Apache CXF进行Web服务学习
  3. 画时序图 visual_时序图的初步了解
  4. Linux 及其它类 Unix 系统的系统服务管理和控制程序(初始化系统/init system)简单梳理
  5. 上传书籍进度信息到服务器...,使用HttpWebRequest实现大文件上传资料.pdf
  6. markdown 行内公式_如何轻松将笔记转为思维导图(Word、Markdown)
  7. python条形堆积图_python – 使用DataFrame.plot显示堆积条形图中...
  8. textureview 缩放_View的双指缩放以及移动
  9. C语言中的指针有什么作用
  10. 26条C++的经典语录,哪几句戳中你的心!