lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Arrastar e soltar

Com a estrutura de trabalho de arrastar e soltar do Android, você pode permitir que usuários movam dados de uma View para outra no layout atual usando um gesto gráfico de arrastar e soltar. A estrutura de trabalho contém uma classe de eventos de arrastar, ouvintes de arrastar e métodos e classes auxiliares.

Embora a estrutura de trabalho seja projetada principalmente para movimentação de dados, é possível usá-la para outras ações de IU. Por exemplo: você pode criar um aplicativo que mistura cores quando o usuário arrasta um ícone colorido sobre outro ícone. No entanto, o resto desse tópico descreve a estrutura de trabalho em termos de movimentação de dados.

Visão geral

Uma operação de arrastar e soltar começa quando o usuário faz um gesto reconhecido como um sinal para começar a arrastar dados. Como resposta, o aplicativo informa ao sistema que a ação de arrastar está começando. O sistema executa um retorno de chamada para o aplicativo para obter uma representação dos dados sendo arrastados. Conforme o dedo do usuário move essa representação (uma “sombra da ação de arrastar”) sobre o layout atual, o sistema envia eventos de arrastar aos objetos de ouvinte de eventos de arrastar e aos métodos de retorno de chamada dos eventos de arrastar associados aos objetos View no layout. Depois que o usuário liberar a sombra da ação de arrastar, o sistema encerrará a operação de arrastar.

Você cria um objeto de ouvinte de evento de arrastar (“ouvintes”) de uma classe que implemente View.OnDragListener. O objeto ouvinte do evento de arrastar para uma View é definido com o método setOnDragListener() do objeto View. Cada objeto View também tem um método de retorno de chamada onDragEvent(). Ambos estão descritos em mais detalhes na seção O ouvinte do evento de arrastar e o método de retorno de chamada.

Observação: Para simplificar, as seções a seguir se referem à rotina que recebe eventos de arrastar como o “ouvinte de eventos de arrastar”, mesmo que ele possa ser na verdade um método de retorno de chamada.

Ao iniciar uma ação de arrastar, incluem-se os dados a mover e os metadados que descrevem esses dados como parte da chamada do sistema. Durante a ação de arrastar, o sistema envia eventos de arrastar aos ouvintes de evento de arrastar ou métodos de retorno de chamada de cada View do layout. Os ouvintes ou métodos de retorno de chamada podem usar os metadados para decidir se querem aceitar os dados quando são soltos. Se o usuário soltar os dados sobre um objeto View e o ouvinte ou método de retorno de chamada dessa View informou previamente ao sistema que quer aceitar a ação de soltar, o sistema enviará os dados ao ouvinte ou método de retorno de chamada em um evento de arrastar.

O aplicativo instrui o sistema a chamar o método startDrag() para iniciar uma ação de arrastar. Isso instrui o sistema a começar a enviar eventos de arrastar. O método também envia os dados sendo arrastados.

Você pode chamar startDrag() para qualquer View anexada ao layout atual. O sistema usa o objeto View apenas para obter acesso às configurações globais no layout.

Depois que o aplicativo chama startDrag(), o resto do processo usa eventos que o sistema envia a objetos View no layout atual.

O processo de arrastar e soltar

Existem essencialmente quatro etapas ou estados no processo de arrastar e soltar:

Iniciado
Em resposta ao gesto do usuário de iniciar uma ação de arrastar, o aplicativo chama startDrag() para instruir o sistema a iniciar uma ação de arrastar. Os argumentos startDrag() fornecem os dados a serem arrastados, os metadados desses dados e um retorno de chamada para desenhar a sombra da ação de arrastar.

Primeiro, o sistema responde executando um retorno de chamada ao aplicativo para obter a sombra da ação de arrastar. Em seguida, ele exibe a sombra da ação de arrastar no dispositivo.

Depois, o sistema envia um evento de arrastar com tipo de ação ACTION_DRAG_STARTED aos ouvintes de eventos de arrastar de todos os objetos View no layout atual. Para continuar a receber eventos de arrastar, inclusive um possível evento de soltar, o ouvinte de eventos de arrastar deve retornar true. Esse retorno registra o ouvinte no sistema. Somente ouvintes registrados continuam a receber eventos de arrastar. Nesse momento, os ouvintes também podem alterar a aparência do objeto View para mostrar que o ouvinte pode aceitar um evento de soltar.

Se o ouvinte de eventos retornar false, não receberá eventos de arrastar para a operação atual até que o sistema enviar um evento de arrastar com tipo de ação ACTION_DRAG_ENDED. Ao enviar false, o ouvinte informa ao sistema que não está interessado na operação de arrastar e não quer aceitar os dados arrastados.

Continuando
O usuário continua a ação de arrastar. Quando a sombra da ação de arrastar cruzar a caixa delimitadora de um objeto View, o sistema enviará um ou mais eventos de arrastar ao ouvinte de eventos de arrastar do objeto View (se ele estiver registrado para receber eventos). O ouvinte pode optar por alterar a aparência do objeto View em resposta ao evento. Por exemplo, se o evento indicar que a sombra da ação de arrastar entrou na caixa delimitadora da View (tipo de ação ACTION_DRAG_ENTERED), o ouvinte poderá reagir destacando sua View.
Solto
O usuário libera a sombra da ação arrastar dentro da caixa delimitadora de uma View que pode aceitar os dados. O sistema envia ao ouvinte do objeto View um evento de arrastar com tipo de ação ACTION_DROP. O evento de arrastar contém os dados passados ao sistema na chamada de startDrag() que iniciou a operação. O ouvinte deverá retornar um true booleano ao sistema se o código para aceitar a ação de soltar for bem-sucedido.

Observe que essa etapa ocorre apenas quando o usuário solta a sombra da ação de arrastar dentro da caixa delimitadora de uma View cujo ouvinte está registrado para receber eventos de arrastar. Se o usuário soltar a sombra da ação de arrastar em qualquer outra situação, nenhum evento de arrastar será enviado ACTION_DROP.

Encerrado
Depois que o usuário soltar a sombra da ação de arrastar e o sistema enviar (se necessário) um evento de arrastar com o tipo de ação ACTION_DROP, o sistema enviará um evento de arrastar com o tipo de ação ACTION_DRAG_ENDED para indicar o término da operação de arrastar. Isso será feito independentemente do local onde o usuário soltar a sombra da ação de arrastar. O evento é enviado a todos os ouvintes registrados para receber eventos de arrastar, mesmo se o ouvinte recebeu o evento ACTION_DROP.

Essas quatro etapas são descritas mais detalhadamente na seção Projetar uma operação de arrastar e soltar.

O ouvinte de eventos de arrastar e o método de retorno de chamada

Uma View recebe eventos de arrastar com um ouvinte de eventos de arrastar que implementa View.OnDragListener ou com seu método de retorno de chamada onDragEvent(DragEvent). Quando o sistema chama o método ou ouvinte, passa-lhes um objeto DragEvent.

Você provavelmente usará o ouvinte na maioria dos casos. Ao projetar IUs, normalmente não são criadas subclasses das classes View, mas o uso do método de retorno de chamada exige que isso seja feito para modificar o método. Por outro lado, é possível implementar uma classe de ouvinte e usá-la com diversos objetos View. Também é possível implementá-la como uma classe anônima em linha. Para definir o ouvinte de um objeto View, chame setOnDragListener().

É possível ter ao mesmo tempo um ouvinte e um método de retorno de chamada para um objeto View. Se isso ocorrer, o sistema chamará primeiro o ouvinte. O sistema não chamará o método de retorno de chamada a menos que o ouvinte retorne false.

A combinação do método onDragEvent(DragEvent) e View.OnDragListener é análoga à combinação de onTouchEvent() e View.OnTouchListener usados com eventos de toque.

Eventos de arrastar

O sistema envia um evento de arrastar como um objeto DragEvent. O objeto tem um tipo de ação que informa ao ouvinte o que está ocorrendo no processo de arrastar e soltar. O objeto contém outros dados, dependendo do tipo de ação.

Para obter o tipo de ação, o ouvinte chama getAction(). Há seis valores possíveis, definidos por constantes na classe DragEvent. Esses valores estão listados na Tabela 1.

O objeto DragEvent também contém os dados fornecidos pelo aplicativo ao sistema na chamada ao startDrag(). Alguns dados são válidos apenas para determinados tipos de ação. Os dados que são válidos para cada tipo de ação são resumidos na Tabela 2. Eles também são descritos em detalhe com o evento em que são válidos na seção Projetar uma operação de arrastar e soltar.

Tabela 1. Tipos de ação DragEvent

getAction() value Significado
ACTION_DRAG_STARTED O ouvinte de eventos de arrastar do objeto View recebe esse tipo de ação de evento logo depois que o aplicativo chama startDrag() e obtém uma sombra da ação de arrastar.
ACTION_DRAG_ENTERED O ouvinte de eventos de arrastar do objeto View recebe esse tipo de ação de evento assim que a sombra da ação de arrastar entra na caixa delimitadora da View. Esse é o primeiro tipo de ação de evento recebido pelo ouvinte quando a sombra da ação de arrastar entra na caixa delimitadora. Se o ouvinte quiser continuar a receber eventos de arrastar para essa operação, deverá retornar um true booleano ao sistema.
ACTION_DRAG_LOCATION O ouvinte de eventos de arrastar do objeto View recebe esse tipo de ação de evento depois de receber um evento ACTION_DRAG_ENTERED enquanto a sombra da ação de arrastar ainda está na caixa delimitadora da View.
ACTION_DRAG_EXITED O ouvinte de eventos de arrastar do objeto View recebe esse tipo de ação de evento depois de receber um ACTION_DRAG_ENTERED e pelo menos um evento ACTION_DRAG_LOCATION, depois que o usuário mover a sombra da ação de arrastar para fora da caixa delimitadora da View.
ACTION_DROP O ouvinte de eventos de arrastar do objeto View recebe esse tipo de ação de evento quando o usuário libera a sombra da ação de arrastar sobre o objeto View. Esse tipo de ação somente será enviado ao ouvinte do objeto View se esse ouvinte retornou um true booleano como resposta ao evento de arrastar ACTION_DRAG_STARTED. Esse tipo de ação não será enviado se o usuário liberar a sombra da ação de arrastar em uma View cujo ouvinte não está registrado, ou se o usuário liberar a sombra da ação de arrastar em qualquer área que não faça parte do layout atual.

O ouvinte deverá retornar true booleano se processar de forma bem-sucedida a ação de soltar. Caso contrário, deverá retornar false.

ACTION_DRAG_ENDED O ouvinte de eventos de arrastar do objeto View recebe esse tipo de ação quando o sistema está encerrando a operação de arrastar. Esse tipo de ação não é necessariamente precedido por um evento ACTION_DROP. Se o sistema enviou um ACTION_DROP, o recebimento do tipo de ação ACTION_DRAG_ENDED não significa que a operação de soltar foi bem-sucedida. O ouvinte deve chamar getResult() para obter o valor que foi retornado como resposta de ACTION_DROP. Se um evento ACTION_DROP não foi enviado, getResult() retorna false.

Tabela 2. Dados válidos de DragEvent por tipo de ação

Valor de getAction() Valor de getClipDescription() Valor de getLocalState() Valor de getX() Valor de getY() Valor de getClipData() valor de getResult()
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       X

Os métodos getAction(), describeContents(), writeToParcel() e toString() sempre retornam dados válidos.

Se um método não contiver dados válidos para um determinado tipo de ação, retornará null ou 0 dependendo do tipo de resultado.

A sombra da ação de arrastar

Durante uma operação de arrastar e soltar, o sistema exibe uma imagem arrastada pelo usuário. Para o movimento de dados, essa imagem representa os dados sendo arrastados. Para outras operações, a imagem representa algum aspecto da operação de arrastar.

Essa imagem é denominada uma sombra da ação de arrastar. Ela é criada com métodos declarados para um objeto View.DragShadowBuilder e então passada ao sistema quando uma ação de arrastar é iniciada usando startDrag(). Como parte de sua resposta a startDrag(), o sistema invoca os métodos de retorno de chamada que você definiu em View.DragShadowBuilder para obter uma sombra da ação de arrastar.

A classe View.DragShadowBuilder tem dois construtores:

View.DragShadowBuilder(View)
Esse construtor aceita qualquer um dos objetos View do aplicativo. O construtor armazena o objeto View no objeto View.DragShadowBuilder. Portanto, durante o retorno de chamada, você pode acessá-lo durante a construção da sombra da ação de arrastar. Ele não precisa ser associado à View (se houver) selecionada pelo usuário para iniciar a operação de arrastar.

Se você usar esse construtor, não precisa estender View.DragShadowBuilder nem modificar seus métodos. Por padrão, você obterá uma sombra da ação de arrastar com a mesma aparência que a View passada como argumento, centralizada no local onde o usuário está tocando a tela.

View.DragShadowBuilder()
Se você usar esse construtor, nenhum objeto View estará disponível no objeto View.DragShadowBuilder (o campo é definido como null). Se você usar esse construtor e não estender View.DragShadowBuilder nem modificar seus métodos, você obterá uma sombra da ação de arrastar invisível. O sistema não gera um erro.

A classe View.DragShadowBuilder tem dois métodos:

onProvideShadowMetrics()
O sistema chama esse método imediatamente após a chamada de startDrag(). Use-o para enviar ao sistema as dimensões e o ponto de contato da sombra da ação de arrastar. O método tem dois argumentos:
dimensões
Um objeto Point. A largura da sombra da ação de arrastar é especificada em x e a altura em y.
ponto de contato
Um objeto Point. O ponto de contato é o local dentro da sombra da ação de arrastar que deve estar sob o dedo do usuário durante a ação de arrastar. Sua posição X é especificada em x e sua posição Y em y
onDrawShadow()
Imediatamente após a chamada de onProvideShadowMetrics() o sistema chama onDrawShadow() para obter a sombra da ação de arrastar. O método tem um único argumento, um objeto Canvas que o sistema constrói com base nos parâmetros informados em onProvideShadowMetrics() Use-o para desenhar a sombra da ação de arrastar no objeto Canvas fornecido.

Para melhorar o desempenho, use um tamanho pequeno para a sombra da ação de arrastar. Para um único item, você pode usar um ícone. Para uma seleção múltipla, você pode usar ícones em uma pilha em vez de imagens completas espalhadas pela tela.

Projetar uma operação de arrastar e soltar

Esta seção mostra detalhadamente como iniciar uma ação de arrastar, como responder a eventos durante a ação de arrastar, como responder a um evento de largar e como encerrar a operação de arrastar e largar.

Iniciar uma ação de arrastar

O usuário inicia uma ação de arrastar com um gesto de arrastar — normalmente, uma pressão longa — em um objeto View. Como resposta, você deve fazer o seguinte:

  1. Se necessário crie um ClipData e um ClipData.Item para os dados sendo movidos. Como parte do objeto ClipData, forneça metadados armazenados em um objeto ClipDescription dentro do ClipData. Para uma operação de arrastar e soltar que não representa movimento de dados, você pode usar null em vez de um objeto real.

    Por exemplo: este snippet de código mostra como responder a uma pressão longa em uma ImageView criando um objeto ClipData que contém a tag ou o rótulo de uma ImageView. Depois desse snippet, o próximo snippet mostra como modificar os métodos em 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)
                );
    
        }
    }
    
  2. O snippet de código a seguir define myDragShadowBuilder Ele cria uma sombra da ação de arrastar para arrastar uma TextView como um retângulo cinza pequeno:
        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);
            }
        }
    

    Observação: Lembre-se de que não é necessário estender View.DragShadowBuilder. O construtor View.DragShadowBuilder(View) cria uma sombra da ação de arrastar padrão com o mesmo tamanho do argumento View passado a ele, com o ponto de contato centralizado na sombra da ação de arrastar.

Responder a um início de ação de arrastar

Durante a operação de arrastar, o sistema despacha eventos de arrastar aos ouvintes de eventos de arrastar dos objetos View no layout atual. Os ouvintes devem reagir chamando getAction() para obter o tipo de ação. No início de uma ação de arrastar, esse método retorna ACTION_DRAG_STARTED.

Em resposta a um evento com o tipo de ação ACTION_DRAG_STARTED, um ouvinte poderia fazer o seguinte:

  1. Chamar getClipDescription() para obter a ClipDescription. Usar os métodos de tipo MIME em ClipDescription para ver se o ouvinte pode aceitar os dados sendo arrastados.

    Se a operação de arrastar e soltar não representar movimento de dados, talvez isso não seja necessário.

  2. Se o ouvinte puder aceitar uma ação de soltar, deverá retornar true. Isso instrui o sistema a continuar a enviar eventos de arrastar ao ouvinte. Se ele não puder aceitar uma ação de soltar, deverá retornar false e o sistema deixará de enviar eventos de arrastar até enviar ACTION_DRAG_ENDED.

Observe que para um evento ACTION_DRAG_STARTED, os métodos de DragEvent a seguir não são válidos: getClipData(), getX(), getY() e getResult().

Processar eventos durante a ação de arrastar

Durante a ação de arrastar, os ouvintes que retornaram true como resposta ao evento de arrastar ACTION_DRAG_STARTED continuam recebendo eventos de arrastar. Os tipos de eventos de arrastar recebidos pelo ouvinte durante a ação de arrastar dependem da localização da sombra da ação de arrastar e da visibilidade da View do ouvinte.

Durante a ação de arrastar, os ouvintes usam principalmente eventos de arrastar para decidir se devem alterar a aparência da View.

Durante a ação de arrastar, getAction() retorna um dentre três valores:

O ouvinte não precisa reagir a nenhum desses tipos de ação. Se o ouvinte retornar um valor para o sistema, ele será ignorado. Veja a seguir algumas diretrizes para responder a cada um desses tipos de ação:

  • Como reposta a ACTION_DRAG_ENTERED ou ACTION_DRAG_LOCATION, o ouvinte pode alterar a aparência da View para indicar que receberá em breve uma ação de soltar.
  • Um evento com o tipo de ação ACTION_DRAG_LOCATION contém dados válidos para getX() e getY(), correspondentes à localização do ponto de contato. O ouvinte poderá usar essas informações para alterar a aparência da parte da View que está no ponto de contato. O ouvinte também poderá usar essas informações para determinar a posição exata em que o usuário vai soltar a sombra da ação de arrastar.
  • Como resposta a ACTION_DRAG_EXITED, o ouvinte deve redefinir todas as alterações de aparência aplicadas como resposta a ACTION_DRAG_ENTERED ou ACTION_DRAG_LOCATION. Isso indica ao usuário que a View deixou de ser um destino para uma ação de soltar iminente.

Responder a uma ação de soltar

Quando o usuário liberar a sombra da ação de arrastar em uma View no aplicativo, e a View tiver informado previamente que poderia aceitar o conteúdo sendo arrastado, o sistema despachará um evento de arrastar a essa View com o tipo de ação ACTION_DROP. O ouvinte deve fazer o seguinte:

  1. Chamar getClipData() para obter o objeto ClipData originalmente fornecido na chamada de startDrag() e armazená-lo. Se as operações de arrastar e soltar não representarem movimento de dados, talvez isso não seja necessário.
  2. Retorne um true booleano para indicar que a ação de soltar foi processada corretamente ou, caso contrário, false. O valor retornado se torna o valor retornado por getResult() para um evento ACTION_DRAG_ENDED.

    Observe que se o sistema não enviar um evento ACTION_DROP, o valor de getResult() para um ACTION_DRAG_ENDED evento será false.

Para um evento ACTION_DROP, getX() e getY() retornam as posições X e Y do ponto da ação de arrastar no momento da ação de soltar, usando o sistema de coordenadas da View que recebeu a ação de soltar.

O sistema permite que o usuário libere a sombra da ação de arrastar em uma View cujo ouvinte não está recebendo eventos de arrastar. Além disso, ele também permite que o usuário libere a sombra da ação de arrastar em regiões vazias da IU do aplicativo ou em áreas fora do aplicativo. Em todos esses casos, o sistema não envia um evento com o tipo de ação ACTION_DROP, embora envie um evento ACTION_DRAG_ENDED.

Responder a um fim de ação de arrastar

Imediatamente depois da liberação da sombra da ação de arrastar pelo usuário, o sistema envia um evento de arrastar a todos os ouvintes de eventos de arrastar no aplicativo com um tipo de ação ACTION_DRAG_ENDED. Isso indica que a operação de arrastar foi concluída.

Cada ouvinte deve fazer o seguinte:

  1. Se um ouvinte alterou a aparência do objeto View durante a operação, deve redefinir a View para a sua aparência padrão. Isso é uma indicação visual para o usuário de que a operação foi concluída.
  2. Opcionalmente, o ouvinte pode chamar getResult() para obter mais informações sobre a operação. Se um ouvinte retornou true como resposta de um evento do tipo de ação ACTION_DROP, getResult() retornará true booleano. Em todos os outros casos, getResult() retornará false booleano, inclusive todos os casos em que o sistema não enviou um evento ACTION_DROP.
  3. O ouvinte deve retornar true booleano ao sistema.

Responder a eventos de arrastar: um exemplo

Todos os eventos são recebidos inicialmente pelo método ou ouvinte de eventos de arrastar. O snippet de código a seguir é um exemplo simples da reação a eventos de arrastar em um ouvinte:

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