AIR2.0拖拽增强

 

AIR文件拖拽的实质

首先让我们来探究一下AIR拖拽中的本质,如下图所示,处于本地系统中的AIR应用,和系统之间通过拖拽方式产生的数据通讯,实际上是通过剪切板进行的。剪切板作为一个中介,如果你拖拽一个文件到AIR应用,那么实质上是将这个文件放到了剪切板,然后AIR应用会从剪切板中获取数据;反之也是如此,当你把文件或数据从AIR应用中拖拽到文件系统中,系统也会根据剪切板中的文件类型决定下一步的操作(比如保存文件)。

拖拽的三个阶段

我们可以把整个拖拽的过程分为三个阶段:启动,拖动和放下。

  1. 启动:用户通过按住鼠标按键从组件或组件中的项目进行拖动,启动拖放操作。涉及的事件包括nativeDragStart 和nativeDragComplete。启动方式是调取NativeDragManager.doDrag(),这个方法调取后,会启动拖拽的过程。
  2. 拖动:用户在按住鼠标按键的同时,将鼠标光标移至其他组件、应用程序,或移至桌面。涉及的事件包括nativeDragUpdate,nativeDragEnter,nativeDragOver,nativeDragExit。其中nativeDragEnter事件会被我们用于检测数据格式,以决定是否允许接受该数据格式。如果格式合法,我们可以调用NativeDragManager.acceptDragDrop()方法,允许该数据在组件上放下。这个时候屏幕上光标的形状会有所变化。
  3. 放下:用户在符合条件的放置目标上释放鼠标。如果是在AIR应用内部放下,涉及的事件包括nativeDragDrop,我们可以捕获这个事件,来获取剪切板中的数据,如果放下的区域在AIR外部,那么将会由操作系统来确定如何处理该操作。

下图描述了NativeDragEvent的各种类型,不同颜色代表这是由不同的对象调度的。

AIR还提供了一个ClipboardFormats类,定义了各种不同的剪切板描述格式,参见下图(这是AIR1.5的版本,在AIR2中增加了一个新的格式,稍后叙述):

按照数据的来源和去处,我们可以将拖拽分为两种类别:拖出和拖入。

拖出操作

拖出的执行过程:

  1. 创建Clipboard对象包裹要传输的数据
  2. 触发mouseDown事件,启动拖拽NativeDragManager.doDrag()
  3. 完成拖拽传输

拖出的代码示例:

 

  
  
  1. private function onMouseDown (event : MouseEvent ) : void {
  2. (myLoader. content as MovieClip ). stop ( );
  3. var bd : BitmapData = new BitmapData ( 600, 500, true,0x000000 );
  4. bd. draw (myLoader );
  5. display = new Bitmap (bd );
  6. var jpg :JPEGEncoder = new JPEGEncoder ( );
  7. var ba : ByteArray = jpg.encode (bd );
  8. file = File.documentsDirectory.resolvePath ( "image.jpg" );
  9. var fileStream :FileStream = new FileStream ( );
  10. fileStream. open (file, FileMode.WRITE );
  11. fileStream. writeBytes (ba, 0,ba. length );
  12. fileStream. close ( );
  13. var transferObject :Clipboard = createClipboard (display );
  14. NativeDragManager.doDrag ( this, transferObject, display. bitmapData, new Point ( - mouseX, - mouseY ) );
  15. }
  16. public function createClipboard (image : Bitmap ) :Clipboard {
  17. var transfer :Clipboard = new Clipboard ( );
  18. transfer.setData ( "bitmap", image, true );
  19. transfer.setData (ClipboardFormats.BITMAP_FORMAT, image. bitmapData, false );
  20. transfer.setData (ClipboardFormats.FILE_LIST_FORMAT, new Array (file ), false );
  21. return transfer;
  22. }

 

该代码的执行过程是,首先有一个正在播放的动画,我用Bitmap获取其中的像素数据,然后用JPEGEncoder编码为JPEG图像文件数据,生成临时文件(这段代码是AIR1.5版本,在AIR2中我们不再需要生成临时文件,而直接使用FilePromise机制)。

拖入操作

拖出的执行过程:

  1. 将一个 Clipboard 对象拖到一个组件上方。
  2. 调度 nativeDragEnter 事件。
  3. 检查数据格式,如果可用,调用 NativeDragManager.acceptDragDrop()。
  4. NativeDragManager 更改鼠标光标,以指示可以放置此对象。
  5. 用户将此对象放在此组件上。
  6. 接收组件调度 nativeDragDrop 事件。
  7. 接收组件从事件对象内的 Clipboard 对象中读取所需格式的数据。

拖入的代码示例:

 

  
  
  1. private function initApp ( ) : void {
  2. this. addEventListener (NativeDragEvent.NATIVE_DRAG_ENTER,onDragIn ); //通常做拖入文件的类型检查
  3. this. addEventListener (NativeDragEvent.NATIVE_DRAG_DROP,onDrop ); //拖拽完成事件
  4. }
  5. private function onDragIn (event :NativeDragEvent ) : void {
  6. var transferable :Clipboard = event.clipboard;
  7. if (transferable.hasFormat (ClipboardFormats.FILE_LIST_FORMAT ) && event.clipboard.getData (ClipboardFormats.FILE_LIST_FORMAT ) [ 0 ].nativePath. split ( "." ) [ 1 ] == "jpg" ) {
  8. NativeDragManager.acceptDragDrop ( this );
  9. } else {
  10. Alert. show ( "不接受的格式" );
  11. }
  12. }
  13. private function onDrop (event :NativeDragEvent ) : void {
  14. var dropfiles : Array= event.clipboard.getData (ClipboardFormats.FILE_LIST_FORMAT ) as Array;
  15. var currentFile :File = dropfiles [ 0 ];
  16. imageSource = currentFile. url;
  17. }

 

该代码的执行过程是,当拖拽目标进入,判断是否合法,如果可以接收该格式,则调取NativeDragManager.acceptDragDrop()。在onDrop方面里,则取得了剪切板中的数据。

AIR2.0中的拖拽增强

AIR1.5的缺憾

  1. 不能拖拽一个不存在的文件
  2. 如果你需要将数据拖拽到桌面,需要先保存为临时文件,然后操作临时文件。

AIR2.0的增强

  1. 引入了File Promise的概念
  2. 你现在可以从AIR2.0创建的应用中拖拽一个不存在的文件(或位于Server上的文件),并且在松开鼠标后提供这个文件的数据
  3. 在ClipboardFormats类中,增加了FILE_PROMISE_LIST_FORMAT,这个专门用于File Promise对象

File Promise简介

File Promise 是这样一种机制,我们可以简单理解为信用卡机制,你先承诺给系统,肯定会提供一个文件,当操作系统接收文件的时候,你再把文件的数据写入。这样我们就省略了要创建一个临时文件的步骤。

在AIR中,并没有一个直接的FilePromise类,而是提供了一个IFilePromise的接口。就是说,只要实现这个接口的类,就具备了File Promise的功能。这对于初学者有些不便,不像File类那样直接就可以使用,不过这也提供了更大的扩展性。你可以为你的各种数据实现File Promise功能。

AIR内部只为这个接口实现了一个类:URLFilePromise,顾名思义,这个类就是帮助你将远程URL的文件保存到本地的。它有两个必须的属性:request定义你要发送的请求(通常是WEB上的一个文件地址),relativePath则定义了要保存的文件名。

下面是一段简单的使用URLFilePromise的代码:

 

  
  
  1. private function doDrag ( ) : void {
  2. var cb :Clipboard = new Clipboard ( );
  3. var items : Array = lt.selectedItems;
  4. var promises : Array = new Array ( );
  5. for each ( var item : Object in items ) {
  6. var fp :URLFilePromise = new URLFilePromise ( );
  7. var req : URLRequest = new URLRequest (item. url );
  8. fp.request = req;
  9. fp.relativePath = item. name;
  10. promises. push (fp );
  11. }
  12. cb.setData (ClipboardFormats.FILE_PROMISE_LIST_FORMAT, promises );
  13. NativeDragManager.doDrag (lt, cb );
  14. }

 

注意代码中使用了数组,这意味着可以允许用户同时拖拽多个远程文件到本地。这已经为实现类似FTP应用桌面端扫清了障碍。

下面我们来探讨实现自定义的File Promise功能类。

自定义File Promise功能类

实现IFilePromise接口

如果你想使用File Promise机制但不能使用URLFilePromise,可以在自定义类中实现该接口。注意数据源是支持同步和异步的,具体罗列如下:

  1. ByteArray (同步)
  2. FileStream (同步或异步)
  3. Socket (异步)
  4. URLStream (异步)

实现该接口,必须实现的方法:

  1. open():IDataInput 返回数据源对象,这个对象必须实现IDataInput接口,如果是异步,还必须实现IEventDispatcher
  2. get relativePath():String 提供一个包含文件名称的路径
  3. get isAsync():Boolean 数据是同步还是异步
  4. close():void 当数据读取完毕或错误时关闭
  5. reportError( e:ErrorEvent ):void 异常时抛出错误

自定义FilePromise类实例

 

  
  
  1. package com.riameeting.promise
  2. {
  3. import flash.desktop.IFilePromise;
  4. import flash.display. Bitmap;
  5. import flash.events. ErrorEvent;
  6. import flash.utils. ByteArray;
  7. import flash.utils. IDataInput;
  8.  
  9. import mx. graphics.codec.JPEGEncoder;
  10.  
  11. public class BitmapFilePromise implements IFilePromise
  12. {
  13. private const fileSize : int = 5000; //size of file data
  14. private var filePath : String = "imagePromise.jpg";
  15.  
  16. public var bmp : Bitmap;
  17.  
  18. public function BitmapFilePromise ( b : Bitmap )
  19. {
  20. bmp = b;
  21. }
  22.  
  23. public function get relativePath ( ) : String
  24. {
  25. return filePath;
  26. }
  27.  
  28. public function get isAsync ( ) : Boolean
  29. {
  30. return false;
  31. }
  32.  
  33. public function open ( ) : IDataInput
  34. {
  35. var jpg :JPEGEncoder = new JPEGEncoder ( );
  36. var ba : ByteArray = jpg.encode (bmp. bitmapData );
  37. ba. position = 0;
  38. return ba;
  39. }
  40.  
  41. public function close ( ) : void { }
  42.  
  43. public function reportError (e : ErrorEvent ) : void { }
  44. }
  45. }

 

  
  
  1. private function onMouseDown (event : MouseEvent ) : void {
  2. (myLoader. content as MovieClip ). stop ( );
  3. var bd : BitmapData = new BitmapData ( 600, 500, true,0x000000 );
  4. bd. draw (myLoader );
  5. display = new Bitmap (bd );
  6. var fp :BitmapFilePromise = new BitmapFilePromise (display );
  7. var cb :Clipboard = new Clipboard ( );
  8. cb.setData (ClipboardFormats.FILE_PROMISE_LIST_FORMAT, [fp ] );
  9. NativeDragManager.doDrag (myLoader, cb );
  10. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值