优才网
【优才原创】Android的拖放机制
2016-04-18 优才学院 优才网
一、拖放机制概述
2 拖放操作是手指触摸屏幕上的某一对象,然后拖动该对象,最后在屏幕的某个位置释放该对象并执行某种操作,如删除、卸载、启动、复制数据等。
2 允许以图形化的手势操作完成某项任务。
2 拖放操作的优势:直观、易用、简化操作步骤。
2 SDK3.0提供了支持拖放操作的编程机制,简称拖放机制,拖放机制是为数据移动设计的,但能够用于其它的UI操作。如Android系统自带的将托盘内图标代表的应用程序以拖放的方式卸载。
2 拖放机制比自编程实现拖放操作更方便,优点包括:
1、提供了对所有View支持拖放操作的API,无需自定义View。
2、系统自动判断手指的位置。
3、由系统自动绘制影子图形。
4、系统提供了拖放对象与目标对象之间传递数据的机制,简化了数据传递的编程。
5、提供了更多的拖放事件,如按下、抬起、释放、进入目标区域、仍在目标区域、离开目标区域、结束拖放等六个事件。并且这些事件由系统捕捉、发送,开发者只需编写处理这些事件的代码。
2 拖放机制包括:
1、响应拖放操作事件的接口;
2、存放拖放操作相关信息的类;
3、启动拖放操作的方法;
4、绘制拖放过程中影子图形的类;
5、传递数据的类。
(二)拖放编程步骤
步骤1、设置被拖放对象的点击或长按或触摸的事件响应代码,在该响应代码中完成以下操作:
1)设置传送给目标对象的数据;
2)设置拖放过程中绘制影子图形的对象;
3)启动拖放操作。
步骤2、编写被拖放对象和拖放目标对象的响应拖放事件的代码。
(三)相关类-ClipData
1、概述
ClipData类用于操作剪贴板中的数据,该类支持进程之间传递数据。在拖放编程中,该类负责被拖动对象与拖动对象之间的数据传递,该类支持传递Uri、Html文本、纯文本等多种类型的数据。
2、常用方法
public static ClipData newPlainText (CharSequence label, CharSequence text) |
|
作用 |
创建一个新的ClipData对象,该对象包含MIMETYPE_TEXT_PLAIN类型的数据。 |
参数 |
label:代表剪贴板中text数据的键。 text:剪贴板中的数据。 |
public ClipData.Item getItemAt (int index) |
|
作用 |
返回剪贴板中的数据。 |
参数 |
index:数据的索引值。index的值范围[0,getItemIndex-1] |
说明 |
若剪贴板中存放的是字符串数据,则由以下代码取出该字符串数据: new ClipData().getItemAt(0).getText().toString(); 其中索引值0表示取出的是剪贴板中第一个 |
public ClipData.Item getItemAt (int index) |
|
作用 |
返回剪贴板中的数据。 |
(四)相关类-DragShadowBuilder
1、概述
在拖拽和放下操作期间,系统会显示一张用户拖动的图片。对于要移动的数据,这张图片就代表了被拖动的数据。对于操作,这张图片就代表了拖动操作的某些外观。
这张图片被叫做影子图形,由DragShadowBuilder对象来创建。
DragShadowBuilder类是View类的内部类。
2、构造方法
public View.DragShadowBuilder (View view) |
|
作用 |
封装了拖拽中各种事件和控件的位置等信息。 |
参数 |
创建用于绘制影子图形的对象,该对象的基类是View,默认情况下,该影子图形与被拖动图形尺寸相同,影子图形的中心点是View对象的中心点坐标。 |
参数 |
view:被拖拽的View对象。 |
3、与拖拽相关的方法
public final boolean startDrag (ClipData data, View.DragShadowBuilder shadowBuilder, Object myLocalState, int flags) |
|
作用 |
开始拖拽指定的View,并把该对象传递给系统。 |
参数 |
创建用于绘制影子图形的对象,该对象的基类是View,默认情况下,该影子图形与被拖动图形尺寸相同,影子图形的中心点是View对象的中心点坐标。 |
参数 |
参数-data:存放数据的剪贴板对象。 shadowBuilder:操作影子图片的对象。 myLocalState:被拖动对象与目标对象之间传递数据的轻量级结构的对象。 |
参数 |
flags:用于控制拖拽操作的类型,当前未定该标志值尚未定义,设置0即可。 |
(五)相关接口-OnDragListener
1、概述
OnDragListener接口用于响应拖拽的相关事件。
2、接口中声明的方法
public boolean onDrag(View view, DragEvent event) |
|
作用 |
封装了拖拽中各种事件和控件的位置等信息。 |
参数 |
view:当前操作的对象,包括被拖拽对象和拖放的目标对象。 |
返回值 |
false将不会接收后续的拖动事件 true将接收后续的拖动事件。 |
(六)相关类-DragEvent
1、概述
系统用DragEvent对象存储拖放事件的相关信息。DragEvent对象包含了一个操作类型,用于告诉监听器在拖放过程中发生的事件。该对象还根据操作类型,包含了其它的数据。
2、拖放事件常量
常量 |
作用 |
ACTION_DRAG_STARTED |
调用startDrag()方法,并且获得了拖拽影子后,View对象的拖拽事件监听器才接收这种事件操作 |
ACTION_DRAG_ENTERED |
进入目标View区域 |
ACTION_DRAG_LOCATION |
停留在目标View区域 |
ACTION_DRAG_EXITED |
离开目标View区域 |
ACTION_DROP |
释放拖拽操作 |
ACTION_DRAG_ENDED |
结束拖拽操作 |
有六种与拖放相关的事件,这些事件在DragEvent类中用六个常量表示,如下表所示:
常量 |
含义 |
ACTION_DRAG_ENTERED |
当拖拽影子刚进入目标View对象的边框时,View对象的拖拽事件监听器会接收这种事件操作类型。 |
ACTION_DRAG_LOCATION |
在View对象收到一个 ACTION_DRAG_ENTERED事件之后,并且拖拽影子依然还在这个对象的边框之内时,这个View对象的拖拽事件监听器会接收这种事件操作类型。 |
ACTION_DRAG_EXITED |
View对象收到一个ACTION_DRAG_ENTERED和至少一个ACTION_DRAG_LOCATION事件之后,这个对象的事件监听器会接受这种操作类型。 |
ACTION_DROP |
当用户在一个View对象之上释放了拖拽影子,这个对象的拖拽事件监听器就会收到这种操作类型。如果这个监听器在响应ACTION_DRAG_STARTED拖拽事件中返回了true,那么这种操作类型只会发送给一个View对象。如果用户在没有被注册监听器的View对象上释放了拖拽影子,或者用户没有在当前布局的任何部分释放操作影子,这个操作类型就不会被发送。如果View对象成功的处理放下事件,监听器要返回true,否则应该返回false。 |
ACTION_DRAG_ENDED |
当系统结束拖拽操作时,View对象拖拽监听器会接收这种事件操作类型。这种操作类型之前不一定是ACTION_DROP事件。如果系统发送了一个ACTION_DROP事件,那么接收ACTION_DRAG_ENDED操作类型不意味着放下操作成功了。监听器必须调用getResult()方法来获得响应ACTION_DROP事件中的返回值。如果ACTION_DROP事件没有被发送,那么getResult()会返回false。 |
3、常用方法
public int getAction () |
|
作用 |
返回拖拽的类型,该类型的可能值是以上的六个常量。 |
public ClipData getClipData() |
|
作用 |
返回ClipData类型的对象,该对象中封装了被拖拽对象的数据。 |
提示 |
ClipData对象在拖拽开始时创建;只有DragEvent. ACTION_DROP事件发生时,getClipData()才能返回startDrag()中第一个参数代表的ClipData对象。 |
public float getX() |
|
作用 |
返回拖拽对象的横坐标。 |
public float getY() |
|
作用 |
返回拖拽对象的纵坐标。 |
public Object getLocateState() |
|
作用 |
获取startDrag()中的第三个参数。 |
二、【案例】
? 目标
在屏幕左上有一个时钟图片,屏幕下边有三个标签,分别代表卸载、启动和分享,如图4所示:
长按时钟,在日志窗口显示“开始拖拽clock,拖动时钟时,如图-5所示:
当拖动时钟进入到“启动”标签区域,在日志窗口显示:clock进入启动区,clock仍在启动区,入图-6所示
当拖动时钟离开“启动”区域,在日志窗口显示:clock离开启动区。松开时钟将显示拖放结束。
提示:
当进入目标区域时,即使没有松手,仍会发生ACTION_DROP事件,因此在图-7中显示“启动clock”。
当进入“卸载”、“分享”区域时,在日志窗口中也将显示类似图-6、图-7的信息。
? 思路
步骤1、MainActivity实现拖放的相关接口
public class MainActivity
extends Activity
implements OnDragListener,OnLongClickListener{
步骤2、定义MainActivity的成员
ImageView
mivClock;
TextView
mtvUninstall,mtvStart,mtvShare;
步骤3、初始化控件
private void initView()
{
//创建显示时钟的控件
mivClock=(ImageView)
findViewById(R.id.ivClock);
//设置时钟拖拽事件的响应
mivClock.setOnDragListener(this);
//设置长按时间的响应
mivClock.setOnLongClickListener(this);
//创建代表分享、启动和卸载的三个控件
mtvShare=(TextView)
findViewById(R.id.tvShare);
mtvStart=(TextView)
findViewById(R.id.tvStart);
mtvUninstall=(TextView)
findViewById(R.id.tvUninstall);
//设置三个TextView响应拖拽事件的代码
mtvShare.setOnDragListener(this);
mtvStart.setOnDragListener(this);
mtvUninstall.setOnDragListener(this);
}
步骤4、编写响应拖放事件的代码
//响应拖拽事件
@Override
public boolean onDrag(View
view, DragEvent event) {
boolean result=true;
//获取拖拽的动作类型值
int action=event.getAction();
switch (action)
{
case DragEvent.ACTION_DRAG_STARTED:
if(view.getId()==R.id.ivClock){
Log.i("main","开始拖拽clock");
}
break;
case DragEvent.ACTION_DRAG_ENTERED:
if(view.getId()==R.id.tvStart){
Log.i("main","clock进入启动区");
}
break;
case DragEvent.ACTION_DRAG_EXITED:
if(view.getId()==R.id.tvStart){
Log.i("main","clock离开启动区");
}
case DragEvent.ACTION_DRAG_LOCATION:
if(view.getId()==R.id.tvStart){
Log.i("main","clock仍在启动区");
}
case DragEvent.ACTION_DROP:
if(view.getId()==R.id.tvShare){
Log.i("main","分享clock");
}else if(view.getId()==R.id.tvStart){
Log.i("main","启动clock");
}else if(view.getId()==R.id.tvUninstall){
Log.i("main","卸载clock");
}
break;
case DragEvent.ACTION_DRAG_ENDED:
Log.i("main","拖拽结束,在drop事件之后发生");
break;
default:
result=false;
break;
}
return result;
}
步骤5、编写响应长按事件的代码
//长按事件响应程序
@Override
public boolean onLongClick(View
view) {
//创建实现阴影的对象
DragShadowBuilder builder=new DragShadowBuilder(view);
/*开始拖拽并把view对象传递给系统。作为响应startDrag()方法的一部分,
*
系统调用在View.DragShadowBuilder对象中定义的回调方法
*
来获取拖拽影子。
*/
view.startDrag(null,
builder, null,
0);
return true;
}
}