Android 用户界面拖放Drag and Drop.docx
- 文档编号:10241899
- 上传时间:2023-02-09
- 格式:DOCX
- 页数:17
- 大小:23.98KB
Android 用户界面拖放Drag and Drop.docx
《Android 用户界面拖放Drag and Drop.docx》由会员分享,可在线阅读,更多相关《Android 用户界面拖放Drag and Drop.docx(17页珍藏版)》请在冰豆网上搜索。
Android用户界面拖放DragandDrop
用Android的拖放框架,能够允许用户使用图形化的拖放手势,把数据从当前布局中的一个View对象中移到另一个View对象中。
这个框架包括:
拖拽事件类、拖拽监听器、以及辅助的方法和类。
尽管这个框架主要是为数据移动设计的,但是你能够把它用于其他的UI操作。
如,你能够创建一个调色应用程序,用户把一个颜色的图标拖到另一个颜色图标之上,完成两个颜色的调配操作。
概要
当用户使用一些被认可的手势信号来开始拖动数据时,一个拖放操作就开始了。
在响应中,应用程序会告诉系统拖动正在启动。
系统就会回调应用程序来获得一个代表被拖动的数据的图形,当用户的手指移到这个代表图形(拖动影子)当前的布局之上时,系统会把拖动事件发给拖动事件监听器对象,并且拖动事件回调方法会跟布局中对应View对象进行关联。
一旦用户释放了拖动影子图形,系统就会结束拖动操作。
从实现View.OnDragListener接口的类中创建一个拖动事件监听器对象。
用View对象的setOnDragListener()方法把拖动事件监听器对象设置给一个View对象。
每个View对象还有一个onDragEvent()回调方法。
这两个方法会在“拖拽事件监听器和回调方法”一节中详细介绍。
注意:
为了简单起见,一下章节用“拖拽事件监听器”作为接收拖拽事件的示例程序,尽管可实践中也可以使用回调方法。
在开始拖动的时候,要把要移动的数据和描述这个数据的元数据作为系统调用的一部分。
拖拽期间,系统把拖拽事件发送给拖拽事件监听器或布局中每个View对象的回调方法。
监听器或回调方法能够使用元数据来判断它们是否能够接受这种数据。
如果用户在一个View对象之上放下数据,并且这个View对象的监听器或回调方法已经告诉系统它要接收这个数据,那么系统就会把数据发送给拖拽事件中的监听器或回调方法。
通过调用startDrag()方法,应用程序会告诉系统开始拖拽的动作。
这样就告诉系统要开始发送拖拽事件了。
这个方法也发送正在拖放的数据。
你能够针对当前布局中任何绑定的View对象调用startDrag()方法。
系统只使用View对象来获取对布局中的全局设置的访问。
一旦你的应用程序调用了startDrag()方法,剩下的过程就是使用系统发送给布局中的View对象的事件。
拖放过程
在拖放过程中有以下四个基本的步骤或状态:
1.开始
在响应用户的屏幕手势中来开始拖拽,应用程序要调用startDrag()方法来告诉系统开始拖拽。
给startDrag()方法提供的参数包括:
被拖拽的数据、这个数据的元数据、以及描画拖拽影子的回调方法。
系统通过响应这个调用,首先返回应用程序需要的拖拽影子。
然后再设备上显示影子。
接下来,系统会把带有ACTION_DRAG_STARTED类型的拖拽事件发送给当前布局中所有的View对象的拖拽事件监听器,如果要继续接收拖拽事件包括可能的放下事件,View对象的拖拽事件监听器必须返回true。
这样就在系统中注册了监听器。
只有被注册的监听器能够继续接收拖拽事件。
这时,监听器也能够改变它的View对象的外观来表示这个对象的监听器能够接收放下事件。
如果拖拽事件监听器返回false,那么一直到系统发送带有ACTION_DRAG_ENDED类型操作的拖拽事件时,这个事件监听器都不会接收当前操作的拖拽事件。
通过发送false返回值,监听器会告诉系统它对这个拖拽操作不感兴趣,并且不会接收被拖拽的数据。
2.持续
用户持续拖拽过程中,当拖拽影子跟一个View对象的边框相交时,系统就会发送一个或多个拖拽事件给View对象的拖拽事件监听器(如果它被注册用来接收这些事件的话)。
监听器也可以选择改变响应事件的View对象的外观。
例如,如果这个事件指示拖拽影子已经进入到接受拖拽事件的View对象的边框内,监听器就能够通过高亮显示它的View对象来做出反应。
3.放下
用户在能够接受数据的View对象的边框内释放拖拽影子,系统就会给View对象的监听器发送一个带有ACTION_DROP操作类型的拖拽事件。
这个拖拽事件包含在startDrag()方法调用中传递给系统的数据。
如果接受成功,监听器就会返回true给系统。
注意,这个步骤只会在用户放下拖放影子的View对象(这个对象被注册用于接受这个拖拽事件)中发生,如果用户在其他的任何不接收这个拖拽事件的地方释放了拖拽影子,就不会有ACTION_DROP拖拽事件发出。
4.结束
用户释放了拖拽影子之后,并且如果需要,系统也会发出了带有ACTION_DROP操作类型的拖拽事件,系统就会发出带有ACTION_DRAG_ENDED操作类型的拖拽事件,指示拖拽操作结束了。
用户释放拖拽影子的时机就是解除注册的时机。
这个事件会发送给每个被注册用于接受这个拖拽事件的监听器,即使这个监听器收到了ACTION_DROP事件。
拖拽事件监听器和回调方法
View对象既可以用实现View.OnDragListener接口的拖放事件监听器,也可以用View对象的onDragEvent(DragEvent)回调方法来接收拖拽事件。
当系统调用这个回调方法或监听器时,都要给它们传递一个DragEvent对象。
在大多数场景中你可能会使用监听器。
因为在设计UI界面时,通常没有View类的子类,而使用回调方法,为了覆写这个方法,就会强制你使用View类及子类。
相比之下,你可以实现一个监听器类,然后再几个不同的View对象中使用。
你还可以把监听器接口作为一个匿名的内部类来实现。
调用setOnDragListener()方法给View对象设置监听器。
View对象能够同时拥有监听器和回调方法,如果发生这种情况,系统会首先调用监听器。
除非监听器返回了false,否则系统不会调用回调方法。
onDragEvent(DragEvent)回调方法和View.OnDragListener监听器的组合跟用于触屏事件的onTouchEvent()回调方法和View.OnTouchListener监听器类似。
拖拽事件
系统用DragEvent对象形式的拖拽事件。
这个对象包含了一个操作类型,它告诉监听器在拖放过程中发生的事情。
这个对象还根据操作类型,包含了其他的数据。
调用getAction()方法能够获得操作类型。
有六种可能的值,在DragEvent类中被定义成常量。
详细见下表1.
DragEvent对象还包含了应用程序在调用startDrag()方法时,提供给系统的数据。
这些数据中有些只对特定的操作类型有效。
在下表2中概要的介绍了对每种操作类型可以获取的有效数据。
表1.DragEvent操作类型
getAction()方法返回值
含义
ACTION_DRAG_STARTED
只在应用程序调用startDrag()方法,并且获得了拖拽影子后,View对象的拖拽事件监听器才接收这种事件操作。
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。
表2.通过操作类型事件获取有效的DragEvent对象的数据,x代表能够获取有效数据。
getAction()Value
getClipDescription()
getLocalState()
getX()
getY()
getClipData()
getResult()
ACTION_DRAG_STARTED
X
X
X
X
ACTION_DRAG_ENTERED
X
X
ACTION_DRAG_LOCATION
X
X
X
X
ACTION_DRAG_EXITED
X
X
ACTION_DROP
X
X
X
X
X
ACTION_DRAG_ENDED
X
X
X
getAction()、describeContents()、writeToParcel()和toString方法始终返回有效的数据。
对于特殊的操作类型,如果一个方法不包含有效的数据,就会根据类型的不同而返回null或0。
拖拽影子
在拖拽和放下操作期间,系统会显示一张用户拖动的图片。
对于要移动的数据,这张图片就代表了被拖动的数据。
对于操作,这张图片就代表了拖动操作的某些外观。
这张图片被叫做拖动影子,使用View.DragShadowBuilder对象的方法来创建它,并且在使用startDrag()方法开始拖拽时,把这个对象传递给系统。
作为响应startDrag()方法的一部分,系统会调用在View.DragShadowBuilder对象中定义的回调方法,来获取拖拽影子。
View.DragShadowBuilder类有两个构造器:
View.DragShadowBuilder(View):
这个构造器接收任意的应用程序的View对象。
这个构造器把View对象保存在View.DragShadowBuilder对象中,以便在回调期间访问这个View对象,来构造拖拽影子。
它(View对象参数)不必跟用户选择的开始拖拽操作的View对象相关联。
如果使用这个构造器,就不必扩展View.DragShadowBuilder类或覆写它的方法。
默认情况,你会获得一个跟传递给构造器的View对象外观相同的拖拽影子。
在用户的触屏位置下方,以出点为中心显示。
View.DragShadowBuilder():
如果使用这个构造器,在ViewDragShadowBuilder对象中没有有效的View对象。
默认情况下,如果使用这个构造器,并且没有扩展View.DragShadowBuilder类或覆写它的方法,那么就会获得一个不可见的拖拽影子,系统不会给出错误。
ViewDragShadowBuilder类有两个方法:
onProvideShadowMetrics():
在你调用startDrag()方法后,系统会立即调用这个方法,给系统发送拖拽影子的尺寸和触点。
这个方法有两个参数:
dimensions:
一个Point对象,其中X代表影子的宽度,Y代表影子的高度;
touch_point:
一个Point对象,这个触点应该是拖拽期间用户手指下方的拖拽影子的位置,X代表x轴的坐标,Y代表y轴的坐标。
onDrawShadow():
调用onProviderShadowMetrics()回调之后,系统会立即调用onDrawShadow()方法来获得拖拽影子。
这个方法有一个画布参数(Canvas对象),系统会使用onProvideShadowMetrics()方法中提供的参数来构造这个Canvas对象,并在这个对象中描画拖拽影子。
要改善性能,就要保持拖拽影子要用小的尺寸。
对于一个单独的项目,可以使用一个图标,对于多项选择,可以是堆栈中的图标而不是分散在屏幕上的完整的图片。
设计拖放操作
本节主要内容如下:
1.如何开始拖拽;
2.在拖拽期间如何响应事件;
3.如何响应落下事件;
4.如何结束拖放操作。
开始拖拽
用户使用一个拖拽手势开始拖拽,通常是在View对象上长按。
在响应中,应该做下列事情:
1.必要时,给要移动的数据创建一个ClipData和ClipData.Item对象,作为ClipData对象的一部分,在ClipData对象内部的ClipDescription对象中保存了元数据。
因为拖放操作不代表数据的移动,因此可以使用null来代替实际的对象。
例如,以下代码段显示了如何在ImageView对象的长按事件上创建一个包含ImageView对象标签的ClipData对象。
//CreateastringfortheImageViewlabel
privatestaticfinalStringIMAGEVIEW_TAG="iconbitmap"
//CreatesanewImageView
ImageViewimageView=newImageView(this);
//SetsthebitmapfortheImageViewfromaniconbitmap(definedelsewhere)
imageView.setImageBitmap(mIconBitmap);
//Setsthetag
imageView.setTag(IMAGEVIEW_TAG);
...
//SetsalongclicklistenerfortheImageViewusingananonymouslistenerobjectthat
//implementstheOnLongClickListenerinterface
imageView.setOnLongClickListener(newView.OnLongClickListener(){
//Definestheonemethodfortheinterface,whichiscalledwhentheViewislong-clicked
publicbooleanonLongClick(Viewv){
//CreateanewClipData.
//Thisisdoneintwostepstoprovideclarity.Theconveniencemethod
//ClipData.newPlainText()cancreateaplaintextClipDatainonestep.
//CreateanewClipData.ItemfromtheImageViewobject'stag
ClipData.Itemitem=newClipData.Item(v.getTag());
//CreateanewClipDatausingthetagasalabel,theplaintextMIMEtype,and
//thealready-createditem.ThiswillcreateanewClipDescriptionobjectwithinthe
//ClipData,andsetitsMIMEtypeentryto"text/plain"
ClipDatadragData=newClipData(v.getTag(),ClipData.MIMETYPE_TEXT_PLAIN,item);
//Instantiatesthedragshadowbuilder.
View.DrawShadowBuildermyShadow=newMyDragShadowBuilder(imageView);
//Startsthedrag
v.startDrag(dragData, //thedatatobedragged
myShadow, //thedragshadowbuilder
null, //noneedtouselocaldata
0 //flags(notcurrentlyused,setto0)
);
}
}
2.以下代码段定义了一个myDragShadowBuilder类,它创建一个用于拖拽TextView对象的小的灰色的矩形作为拖拽影子:
privatestaticclassMyDragShadowBuilderextendsView.DragShadowBuilder{
//Thedragshadowimage,definedasadrawablething
privatestaticDrawableshadow;
//DefinestheconstructorformyDragShadowBuilder
publicMyDragShadowBuilder(Viewv){
//StorestheViewparameterpassedtomyDragShadowBuilder.
super(v);
//CreatesadraggableimagethatwillfilltheCanvasprovidedbythesystem.
shadow=newColorDrawable(Color.LTGRAY);
}
//Definesacallbackthatsendsthedragshadowdimensionsandtouchpointbacktothe
//system.
@Override
publicvoidonProvideShadowMetrics(Pointsize,Pointtouch)
//Defineslocalvariables
privateintwidth,height;
//SetsthewidthoftheshadowtohalfthewidthoftheoriginalView
width=getView().getWidth()/2;
//SetstheheightoftheshadowtohalftheheightoftheoriginalView
height=getView().getHeight()/2;
//ThedragshadowisaColorDrawable.Thissetsitsdimensionstobethesameasthe
//Canvasthatthesystemwillprovide.Asaresult,thedragshadowwillfillthe
//Canvas.
shadow.setBounds(0,0,width,height);
//Setsthesizeparameter'swidthandheightvalues.Thesegetbacktothesystem
//throughthesizeparameter.
size.set(width,height);
//Setsthetouchpoint'spositiontobeinthemiddleofthedragshadow
touch.set(width/2,height/2);
}
//DefinesacallbackthatdrawsthedragshadowinaCanvasthatthesystemconstructs
//fromthedimensionspassedinonProvideShadowMetrics().
@Override
publicvoidonDrawShadow(Canvascanvas){
//DrawstheColorDrawableintheCanvaspassedinfromthesystem.
shadow.draw(canvas);
}
}
注意:
不必扩展View.DragShadowBuilder类,因为构造器View.DragShadowBuilder(View)会创建一个默认的跟传递给它的View对象相同尺寸的拖拽影子,而且触点在拖拽影子的中心。
对拖拽开始的响应
在拖拽操作期间,系统会分发拖拽事件给当前布局中View对象的拖拽事件监听器。
监听器应该通过调用getAction()方法对获得的操作类型做出反应。
在拖拽开始时,这个方法返回ACTION_DRAG_STARTED.
在对ACTION_DRAG_STARTED操作类型做出的响应中,监听器应该做下列事情:
1.调用getClipDescription()方法来获得ClipDescription对象,使用ClipDescription对象中的MIME类型方法来判断监听器是否能够接收被拖拽的数据。
如果拖拽操作不代表要移动的数据,这个判断就不是必须的了。
2.如果监听器能够接受落下事件,它应该返回true。
这样就告诉系统可以继续给这个监听器发送拖拽事件
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 用户界面拖放Drag and Drop 用户界面 拖放 Drag