zoukankan      html  css  js  c++  java
  • Android API Guides---Drag and Drop

    Drag and Drop

    随着Android拖/放框架,能够同意用户将数据从一个视图使用图形拖动移动到还有一个查看当前布局和下降的手势。

    该框架包含一个拖放事件类,拖累听众和辅助方法和类。




    尽管该框架的主要设计用于数据移动,你能够将其用于其它UI操作。比如。您能够创建当用户拖动过还有一个图标颜色图标颜色混合的应用程序。本主题的其余部分,可是,描写叙述了数据移动方面的框架。




    概观


    一个拖放操作開始时用户进行,你承认作为一个信号,開始拖动数据的一些姿态。对此。您的应用程序告诉拖动正在启动系统。系统调用返回到您的应用程序来获得数据的表示被拖动。

    当用户的手指在当前布局移动这表示(“拖影”),系统会发送拖动事件与布局中的视图对象关联的拖动事件侦听器对象和拖曳事件的回调方法。

    一旦用户释放拖动阴影,系统结束拖动操作。




    您从实现View.OnDragListener类创建一个拖动事件侦听器对象(“监听器”​​)。

    您能够设置拖动事件侦听器对象与View对象的setOnDragListener()方法的视图。每一个视图对象也有一个onDragEvent()回调方法。这两种中更具体的部分中的拖动事件监听器和回调方法说明。




    注意:为了简单起见,以下的部分是指接收拖动事件为“拖拽事件侦听器”的例行程序,即使它实际上可能是一个回调方法。


    当您開始拖动,既包含正在移动的数据和元数据描写叙述这个数据作为调用系统的一部分。在拖动期间,系统会发送拖拽事件拖拽事件侦听器或布局的每一个View的回调方法。听众或回调方法能够使用​​元数据来决定他们是否愿意当它降到接受数据。假设用户在一个视图对象丢弃数据,以及查看对象的监听器或回调方法曾经告诉它要接受降系统,那么系统中的数据发送到一个拖动事件侦听器或回调方法。


    您的应用程序告诉系统通过调用startDrag()方法来启动一个拖累。

    这告诉系统開始发送拖动事件。该方法还发送您所拖动的数据。


    你能够调用的startDrag()在当前布局中连接的不论什么视图。该系统仅仅使用视图对象来获取在布局訪问全局设置。


    一旦你的应用程序调用的startDrag()。该过程的其余部分将使用该系统发送到视图对象在当前布局事件。


    拖/放过程


    基本上有四个步骤或状态的拖放过程:


    入门
    为了响应用户的手势開始拖累,应用程序调用的startDrag()来告诉系统启动一个拖累。參数的startDrag()提供到被拖动数据。元数据该数据,并用于绘制拖影的回调。


    该系统首先通过调用返回到您的应用程序来获得一拖影响应。然后,它显示设备上的拖影。




    接下来,系统发送到ACTION_DRAG_STARTED拖动事件侦听器在当前布局中的全部视图对象的动作类型拖曳事件。要继续接收拖动事件,包含可能的放置事件。一拖事件监听器必须返回true。这将注冊与系统的监听器。

    仅仅有注冊听众继续接收拖动事件。此时,听众也能够改变他们的查看对象的外观表明听众能够接受的下降事件。


    假设拖拽事件侦听器返回false,那么将不会收到拖动事件当前操作。直到系统发送动作类型ACTION_DRAG_ENDED拖曳事件。通过发送假,听众告诉系统。这是不感兴趣的拖动操作。而且不希望接受拖动的数据。


    继续
    用户能够继续拖动。

    因为拖影相交的视图对象的边框,系统会发送一个或多个拖动事件查看对象的拖动事件侦听器(假设注冊的接收事件)。聆听者能够选择改变响应事件视图对象的外观。

    比如,假设该事件表明拖影已进入视图(动作类型ACTION_DRAG_ENTERED)的边框,听众能够通过突出其查看反应。
    下降
    用户释放一种观点觉得能够接受数据的边界框内拖影。该系统发送查看对象的监听器与动作类型ACTION_DROP拖曳事件。

    拖动事件包括传递给系统调用的startDrag()启动该操作的数据。

    监听器估计将布尔值true返回系统假设接受降码成功。
    须要注意的是,假设用户删除了一个视图,其监听器注冊接收拖动事件的边界框内拖影这一步仅仅发生。假设用户释放在不论什么其它情况下拖动阴影。则发送没有ACTION_DROP拖拽事件。


    截至
    后用户释放拖动阴影,而且系统发送出后(假设须要)与操作类型ACTION_DROP拖拽事件时,系统发出一个拖拽事件与动作类型ACTION_DRAG_ENDED以指示拖动操作已经结束。不管在哪里。用户公布的拖影这样做。事件被发送到每个被注冊以接收拖动事件侦听器,即使听者接收的ACTION_DROP事件。


    每一个这些四个步骤进行更具体的部分设计一个拖放操作说明。


    拖动事件侦听器和回调方法


    A浏览接收到不论什么实现View.OnDragListener或与其onDragEvent(的dragEvent)回调方法拖动事件监听拖动事件。当系统调用该方法或监听器,它传递给他们一个DragEvent对象。




    你可能会想使用监听器在大多数情况下。

    当你设计的用户界面,你平时不继承视图类,但为了要覆盖的方法使用回调方法迫使你这样做。相比較而言,你能够实现一个监听器类,然后用几个不同的视图对象使用它。您还能够实现它作为一个匿名内嵌类。

    要设置视图对象的监听器,调用setOnDragListener()。


    你能够同一时候拥有监听器和查看对象的回调方法。假设出现这样的情况。系统将首先调用监听程序。除非监听器返回false系统不会调用回调方法。




    所述onDragEvent(的dragEvent)方法View.OnDragListener和组合类似于与触摸事件中使用的onTouchEvent()和View.OnTouchListener的组合。




    拖动事件


    该系统发出一个拖动事件的DragEvent对象的形式。该对象包括动作类型。告诉什么在拖/放过程中发生的监听器。

    所述对象包括的其它数据,这取决于操作类型。


    为了让操作类型。侦听器调用的getAction()。

    有六种可能的值。通过DragEvent类常量定义。这些列于表1。


    该DragEvent对象还包括您的应用程序提供给系统调用的startDrag数据()。

    有些数据仅仅对特定的操作类型有效。

    这是有效的每一个动作类型的数据总结在表2中还具体地,这就是它在部分设计一个拖放操作有效的事件说明。


    表1的dragEvent动作类型

    的getAction()值含义
    ACTION_DRAG_STARTED View对象的拖动事件侦听器接收应用程序调用的startDrag仅仅是此事件后,动作类型(),并得到一拖影。
    ACTION_DRAG_ENTERED View对象的拖动事件侦听器接收到这个事件动作类型时拖影刚刚进入视图的边框。这是当拖影进入边界框听者接收第一事件动作类型。

    假设听众想继续接收拖动事件对于此操作,它必须返回布尔真系统。
    它收到ACTION_DRAG_ENTERED事件之后,同一时候拖动阴影仍是观的边框内ACTION_DRAG_LOCATION View对象的拖动事件侦听器接收到这个事件操作类型。
    它接收ACTION_DRAG_ENTERED后ACTION_DRAG_EXITED View对象的拖动事件侦听器接收到这个事件动作类型的至少一个ACTION_DRAG_LOCATION事件。之后用户移动视图的边框外拖影。


    当用户释放了View对象拖影ACTION_DROP View对象的拖动事件侦听器接收到这个事件操作类型。

    这个动作类型仅仅发送到一个视图对象的侦听器,假设听众响应ACTION_DRAG_STARTED拖动事件返回布尔值true。假设用户释放上的视图。其侦听未注冊在拖影不发送此动作类型,或者假设用户释放对不论什么不是当前布局的一部分的拖影。
    监听估计。假设它成功处理下降返回布尔值true。否则。它应该返回false。


    ACTION_DRAG_ENDED View对象的拖动事件侦听器接收当系统结束拖动操作此事件操作类型。

    此动作类型不必由一个ACTION_DROP事件之前。

    假设系统发送一个ACTION_DROP,接收ACTION_DRAG_ENDED动作类型并不意味着下拉操作成功。

    监听器必须调用的getResult()来获取是响应ACTION_DROP返回的值。

    假设没有发送的ACTION_DROP事件,那么的getResult()返回false。
    通过操作类型表2.有效的dragEvent数据



    getAction() value getClipDescription()value getLocalState()value getX()value getY()value getClipData()value getResult()value
    ACTION_DRAG_STARTED X X X      
    ACTION_DRAG_ENTERED X X 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  
                 
    该的getAction(),describeContents(),writeToParcel()和toString()方法总是返回有效的数据。


    假设一个方法不包括有效的数据为特定的操作类型,则返回null或0。这取决于其结果类型。



    投影

    在一个拖放操作。系统将显示用户拖动图像。对于数据移动。这个形象代表被拖动的数据。

    对于其它操作,图像表示拖动操作的某些方面。


    该图像被称为拖影。

    你和你声明的View.DragShadowBuilder对象的方法创建它。然后把它传递给系统,当您使用的startDrag启动一拖()。

    作为其的startDrag()反应的一部分,该系统调用你已经在View.DragShadowBuilder定义为获得​​一拖影的回调方法。




    该View.DragShadowBuilder类有两个构造函数:


    View.DragShadowBuilder(查看)
    此构造函数接受你的不论什么应用程序的视图对象。构造函数存储在View.DragShadowBuilder对象视图对象,所以回调期间,您能够为您建造拖影訪问它。它不具有要与显示有关(假设有的话)。该用户选择,以便開始拖曳操作。


    假设您使用此构造函数。你不必延长View.DragShadowBuilder或覆盖它的方法。默认情况下,你会得到一个具有美观,你作为參数传递。当中用户触摸屏幕的位置居中下查看同样的拖影。


    View.DragShadowBuilder()
    假设使用此构造,没有查看对象在View.DragShadowBuilder对象(字段设置为null)可用。假设使用此构造函数,你不延长View.DragShadowBuilder或覆盖它的方法,你会得到一个无形的阻力阴影。该系统不给出错误。


    该View.DragShadowBuilder类有两个方法:


    onProvideShadowMetrics()
    该系统调用这种方法调用的startDrag后马上()。

    用它来发送到系统拖影的尺寸和触摸点。该方法有两个參数:
    外形尺寸
    的Point对象。拖影那张宽x和它的高度去y中。
    接触点
    的Point对象。

    触摸点是在拖影。应该是在拖动期间用户的手指下中的位置。其X位置变为以x和Y轴的位置去y中
    onDrawShadow()
    调用onProvideShadowMetrics()系统调用onDrawShadow后马上()来获得拖影本身。该方法仅仅有一个參数,一个Canvas对象,该系统从你onProvideShadowMetrics提供的參数()用它来绘制拖影在所提供的Canvas对象构造。
    为了提高性能,你应该保持阻力的大小影小。对于单个项目。您可能须要使用一个图标。对于多重选择,您可能须要使用图标堆叠中的,而不是全面的图像分布在屏幕上。




    设计一个拖放操作


    本节说明一步一步怎样启动一个拖累。怎样在拖动过程中响应事件,怎样应对drop事件,以及怎样结束拖放操作。


    開始一拖


    在用户開始与拖动动作一拖,平时长按,在一个视图对象。作为回应,你应该做到下面几点:


    依据须要。创建一个用于数据的ClipData和ClipData.Item移动。作为ClipData对象的一部分。存储在ClipData内ClipDesc​​ription对象供给的元数据。

    对于拖放不代表数据移动操作时。您可能要改为null,则使用一个实际的对象。
    比如,以下的代码片段展示了怎样通过创建一个包括的ImageView的标签或标签的ClipData对象长按响应上ImageView的。以下这个片段中,接下来的片段展示了怎样覆盖View.DragShadowBuilder方法:

    // 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)
                );
    
        }
    }

    以下的代码片段定义了我的DragShadowBuilder它为拖动一个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(查看)创建一个默认拖影是这种大小传递给它,用拖影中心的接触点查看參数同样。




    回应一拖開始


    在拖动操作时。系统分派拖动事件在当前布局视图的对象的拖动事件侦听器。听众应该调用的getAction()来获取操作类型反应。在拖动開始时。此方法将返回ACTION_DRAG_STARTED。


    为了应对与ACTION_DRAG_STARTED动作类型的事件,侦听器应做到下面几点:


    呼叫getClipDesc​​ription()来获得ClipDesc​​ription。使用MIME类型方法ClipDesc​​ription。看看听众能接受被拖动的数据。
    假设拖拽操作不表示数据移动,这可能不是必要的。
    假设听众能够接受的下降,但应返回true。这告诉系统继续发送拖动事件监听器。假设它不能接受的下降,它应该返回false,系统将停止发送拖动事件。直到它发出ACTION_DRAG_ENDED。
    注意,对于一个ACTION_DRAG_STARTED事件,这些以下的dragEvent方法是无效的:getClipData(),的getX(),的getY(),和的getResult()。


    在拖动过程中处理事件


    在拖动期间,在应对ACTION_DRAG_STARTED拖动事件返回真正的监听器继续接收拖动事件。在拖动过程中侦听器可以接收的类型拖动事件取决于拖影的位置和听者的视图的可见性。


    在拖动期间。听众主要是使用拖放事件,以决定他们是否应该改变他们查看的外观。


    在拖动期间。的getAction()返回三个值中的一个:


    ACTION_DRAG_ENTERED:侦听器接收到这个时候接触点(用户的手指下方的屏幕上的点)已经进入听者的视图的边框。


    ACTION_DRAG_LOCATION:一旦侦听器可以接收ACTION_DRAG_ENTERED事件,它收到一个AACTION_DRAG_EXITED事件之前,它的每个接触点移动时接收到一个新的ACTION_DRAG_LOCATION事件。

    所述的getX()和的getY()方法返回的X和触摸点的Y坐标。
    ACTION_DRAG_EXITED:该事件被发送给先前接收ACTION_DRAG_ENTERED,后拖影不再是听众的观点的边框内的监听器。


    听者并不须要不论什么这些操作类型的反应。假设侦听返回一个值给系统,它被忽略。

    以下是应对这些动作类型的一些指导原则:


    响应于ACTION_DRAG_ENTERED或ACTION_DRAG_LOCATION。听众能够改变视图的外观以指示它是要接收的下降。
    与动作类型ACTION_DRAG_LOCATION事件包括的getX()和的getY()的有效数据,相应于触摸点的位置。听者可能要使用该信息来改变视图是在所述触摸点的那部分的外观。听者也能够使用此信息来确定用户将要删除拖影的确切位置。
    为了应对ACTION_DRAG_EXITED。听者应该重置不论什么改变的外观它响应应用于ACTION_DRAG_ENTERED或ACTION_DRAG_LOCATION。这表明该视图不再是一个迫在眉睫的放置目标用户。


    回应下降


    当用户释放在应用视图中的拖影。以及查看此前报道称。它能够接受的内容被拖动。系统调度拖动事件到查看与操作类型ACTION_DROP。监听器应做到下面几点:


    呼叫getClipData()来获取)最初在通话供给的startDrag(该ClipData对象存储。假设拖拽操作不表示数据移动,这可能不是必要的。
    返回布尔值true,表明下跌被成功处理,或者布尔值false。假设事实并不是如此。返回的值将成为一个ACTION_DRAG_ENDED事件)通过的getResult(返回的值。
    请注意。假设系统没有发送一个ACTION_DROP事件。的getResult()的值用于ACTION_DRAG_ENDED事件为假。


    用于ACTION_DROP事件。的getX()和的getY()返回X和在下降的时刻的拖动点的Y位置,使用该接收到的下拉视图的坐标系。


    该系统确实同意用户公布在查看其侦听器未接收拖动事件拖影。它也将同意用户公布应用程序的用户界面的空白区域,或在您的应用程序以外的地区拖影。在全部这些情况下。系统不发送与操作类型ACTION_DROP一个事件。尽管它发送一个ACTION_DRAG_ENDED事件。




    回应一拖究竟


    用户释放拖动阴影紧接着。系统会发送拖曳事件的全部应用程序中的拖动事件侦听器,具有ACTION_DRAG_ENDED的动作类型。

    这表明拖动操作已经结束。


    每一个听者应做到下面几点:


    假设听者在操作过程中改变了查看对象的外观。它应该又一次查看到其默认外观。这是一个视觉指示,即该操作是通过用户。


    侦听器能够任意调用的getResult(),以了解很多其它的操作。假设听众响应返回真实的动作类型ACTION_DROP的事件。那么的getResult()将返回布尔值true。在其它情况下,的getResult()返回布尔值false。包含在系统没有发出一个ACTION_DROP事件的不论什么情况。


    监听器应该返回布尔值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.OnDragListener {
    
        // 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;
    
                    }
    
                    // Returns false. During the current drag and drop operation, this View will
                    // not receive events again until ACTION_DRAG_ENDED is sent.
                    return false;
    
                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;
    
                case DragEvent.ACTION_DRAG_LOCATION:
    
                    // Ignore the event
                    return true;
    
                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;
    
                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;
    
                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;
    
                // An unknown action type was received.
                default:
                    Log.e("DragDrop Example","Unknown action type received by OnDragListener.");
                    break;
            }
            
            return false;
        }
    };



    getAction() value getClipDescription()value getLocalState()value getX()value getY()value getClipData()value getResult()value
    ACTION_DRAG_STARTED X X X      
    ACTION_DRAG_ENTERED X X 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  
  • 相关阅读:
    HDU 2104 hide handkerchief
    HDU 1062 Text Reverse 字符串反转
    HDU 1049
    HDU 1096 A+B for Input-Output Practice (VIII)
    POJ 1017
    C/C++一些难为人知的小细节
    小刘同学的第十二篇博文
    小刘同学的第十一篇博文
    小刘同学的第十篇博文
    小刘同学的第九篇日记
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7356075.html
Copyright © 2011-2022 走看看