zoukankan      html  css  js  c++  java
  • Android 用户界面---拖放(Drag and Drop)(三)

    设计拖放操作

    本节主要内容如下:

    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(newView.OnLongClickListener(){

        // Defines the one method for the interface, which is called when the View is long-clicked
        publicboolean 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.DrawShadowBuilder 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
        privatestatic Drawable shadow;

            // Defines the constructor for myDragShadowBuilder
            publicMyDragShadowBuilder(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
            publicvoid onProvideShadowMetrics (Point size,Point touch)
                // Defines local variables
                privateint 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
            publicvoid 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);

    ...

    protectedclass myDragEventListener implements View.OnDragEventListener{

        // This is the method that the system calls when it dispatches a drag event to the
        // listener.
        publicboolean onDrag(View v,DragEvent event){

            // Defines a variable to store the action type for the incoming event
            finalint action =event.getAction();

            // Handles each of the expected events
            switch(action){

                caseDragEvent.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;

                caseDragEvent.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;

                    caseDragEvent.ACTION_DRAG_LOCATION:

                    // Ignore the event
                        return(true);

                    break;

                    caseDragEvent.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;

                    caseDragEvent.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;

                    caseDragEvent.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;
            };

       };

    };

  • 相关阅读:
    macos linux 命令行显示当前全路径方法
    mac 下面使用apidoc 使用
    du 统计文件夹大小
    mac 共享文件和mount挂载数据
    linux与linux、windows之间文件共享的几种方式
    Yaf安装和配置
    设计模式之 里氏替换原则
    设计模式之单一职责原则
    微信支付 遇到问题总结
    bash shell 快捷键
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4803484.html
Copyright © 2011-2022 走看看