As seções a seguir explicam alguns conceitos importantes do processo de arrastar e soltar.
Processo de arrastar e soltar
Existem quatro etapas ou estados no processo de arrastar e soltar: iniciado, em andamento, descartado e encerrado.
- Iniciado
Em resposta ao gesto de arrastar de um usuário, o app chama
startDragAndDrop()para instruir o sistema a iniciar uma operação de arrastar e soltar. Os argumentos do método fornecem:- Os dados a serem arrastados.
- Um callback para mostrar a ação de arrastar
- Metadados que descrevem os dados arrastados
- O sistema responde chamando o aplicativo para extrair uma ação de arrastar. Em seguida, o sistema mostra a ação de arrastar no dispositivo.
- Depois, o sistema envia um evento de arrastar com o tipo de ação
ACTION_DRAG_STARTEDpara o listener de eventos de arrastar de todos os objetosViewno layout atual. Para continuar a receber eventos de arrastar, incluindo um possível evento de soltar, o listener de eventos de arrastar precisa retornartrue. Isso registra o listener junto ao sistema. Somente listeners registrados continuam a receber eventos de arrastar. Neste ponto, os listeners também podem mudar a aparência do objetoViewdo destino de soltar para mostrar que a visualização pode aceitar um evento de soltar. - Se o listener de eventos de arrastar retornar
false, ele não vai receber eventos de arrastar para a operação atual até que o sistema envie um evento de arrastar com o tipo de açãoACTION_DRAG_ENDED. Ao retornarfalse, o listener informa ao sistema que ele não tem interesse na operação de arrastar e soltar e não quer aceitar os dados arrastados.
- Continuando
- O usuário continua a arrastar. Conforme a ação de arrastar cruza a caixa delimitadora
de um destino de soltar, o sistema envia um ou mais eventos de arrastar ao listener
de eventos de arrastar do destino. O listener pode mudar a aparência do
destino de soltar
Viewem resposta ao evento. Por exemplo, se o evento indicar que a ação de arrastar entra na caixa delimitadora do destino de soltar (tipo de açãoACTION_DRAG_ENTERED), o listener pode reagir destacando aView. - Descarte concluído
- O usuário solta a ação de arrastar dentro da caixa delimitadora de um destino de soltar. O sistema envia ao listener do destino de soltar um evento de arrastar com o tipo de ação
ACTION_DROP. O objeto de evento de arrastar contém os dados que são transmitidos ao sistema na chamada parastartDragAndDrop()que inicia a operação. Espera-se que o listener retorne o booleanotrueao sistema se o processamento dos dados descartados for concluído pelo listener. : Essa etapa só ocorre se o usuário soltar a ação de arrastar dentro da caixa delimitadora de umaViewcujo listener está registrado para receber eventos de arrastar (um destino de soltar). Se o usuário soltar a ação de arrastar em qualquer outra situação, nenhum evento de arrastarACTION_DROPserá enviado. - Finalizado
Depois que o usuário solta a sombra de arraste e após o sistema enviar
um evento de arrastar com tipo de ação
ACTION_DROP. Se necessário, o sistema envia um evento de arrastar com tipo de açãoACTION_DRAG_ENDEDpara indicar que a operação de arrastar e soltar acabou. Isso é feito independente de onde o usuário solta a ação de arrastar. O evento é enviado para todos os listeners registrados para receber eventos de arrastar, mesmo se o listener também receber o eventoACTION_DROP.
Cada uma dessas etapas é descrita em mais detalhes na seção Uma operação de arrastar e soltar.
Eventos de arrastar
O sistema envia um evento de arrastar na forma de um objeto DragEvent, que
contém um tipo de ação que descreve o que está acontecendo no processo de arrastar e soltar. Dependendo do tipo de ação, o objeto também pode conter outros dados.
Os listeners de eventos de arrastar recebem o objeto DragEvent. Para ver o tipo de ação,
os listeners chamam
DragEvent.getAction().
Há seis valores possíveis definidos por constantes na classe DragEvent, que são descritos na tabela 1:
Tabela 1. Tipos de ação de DragEvent.
| Tipo de ação | Significado |
|---|---|
ACTION_DRAG_STARTED |
O aplicativo chama startDragAndDrop() e recebe
uma ação de arrastar. Se o listener quiser continuar recebendo eventos de arrastar
para essa operação, é necessário retornar o valor booleano true ao
sistema.
|
ACTION_DRAG_ENTERED |
A ação de arrastar entra na caixa delimitadora da
View do listener de eventos de arrastar. Esse é o primeiro tipo de ação de evento que o listener
recebe quando a ação de arrastar entra na caixa delimitadora.
|
ACTION_DRAG_LOCATION |
Depois de um
evento ACTION_DRAG_ENTERED, a ação de arrastar ainda
está dentro da caixa delimitadora da
View do listener de eventos de arrastar.
|
ACTION_DRAG_EXITED |
Após um evento ACTION_DRAG_ENTERED e pelo menos um
ACTION_DRAG_LOCATION, a ação de arrastar é movida
para fora da caixa delimitadora da
View do listener de eventos de arrastar.
|
ACTION_DROP |
A ação de arrastar é solta na
View do listener de eventos de arrastar. Esse tipo de ação é enviado ao listener de um objeto View
somente se o listener retornar o valor booleano
true em resposta ao
evento de arrastar ACTION_DRAG_STARTED. Esse tipo de ação não é
enviado se o usuário solta a ação de arrastar em uma View
cujo listener não está registrado ou se ele solta a ação de arrastar
em algo que não faz parte do layout atual.
O listener retorna o booleano |
ACTION_DRAG_ENDED |
O sistema está finalizando a operação de arrastar e soltar. Esse tipo de ação
não é necessariamente precedido por um evento ACTION_DROP. Se
o sistema enviar um ACTION_DROP, o recebimento do
tipo de ação ACTION_DRAG_ENDED não implica que a
operação de soltar foi concluída. O listener precisa chamar
getResult(),
conforme mostrado na tabela 2, para receber o valor
retornado em resposta a ACTION_DROP. Se um
evento ACTION_DROP não for enviado, getResult() vai retornar false.
|
O objeto DragEvent também contém os dados e metadados que o aplicativo
fornece ao sistema na chamada do método startDragAndDrop(). Alguns dados são válidos apenas para determinados tipos de ação, conforme resumido na tabela 2. Para mais
informações sobre eventos e os dados associados, consulte a seção Uma
operação de arrastar e soltar.
Tabela 2. Dados válidos de DragEvent por tipo de ação
getAction()valor |
getClipDescription()valor |
getLocalState()valor |
getX()valor |
getY()valor |
getClipData()valor |
getResult()valor |
|---|---|---|---|---|---|---|
ACTION_DRAG_STARTED |
✓ | ✓ | ||||
ACTION_DRAG_ENTERED |
✓ | ✓ | ||||
ACTION_DRAG_LOCATION |
✓ | ✓ | ✓ | ✓ | ||
ACTION_DRAG_EXITED |
✓ | ✓ | ||||
ACTION_DROP |
✓ | ✓ | ✓ | ✓ | ✓ | |
ACTION_DRAG_ENDED |
✓ | ✓ |
Os métodos DragEvent getAction(),
describeContents(),
writeToParcel()
e toString() sempre
retornam dados válidos.
Se um método não contiver dados válidos para um tipo de ação específico, ele retornará
null ou 0, dependendo do tipo de resultado.
Ação de arrastar
Durante uma operação de arrastar e soltar, o sistema exibe uma imagem que o usuário arrasta. 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.
A imagem é chamada de ação de arrastar. Você pode a criar usando os métodos que declara para
um
objeto
View.DragShadowBuilder. Você transmite o builder ao sistema quando inicia uma operação de arrastar e soltar
usando startDragAndDrop(). Como parte da resposta a
startDragAndDrop(), o sistema invoca os métodos de callback que você define em
View.DragShadowBuilder para obter uma ação de arrastar.
A classe View.DragShadowBuilder tem dois construtores:
View.DragShadowBuilder(View)Esse construtor aceita todos os objetos
Viewdo aplicativo. O construtor armazena o objetoViewno objetoView.DragShadowBuilderpara que os callbacks possam o acessar a fim de construir a ação de arrastar. A visualização não precisa ser umViewque o usuário seleciona para iniciar a operação de arrastar.Se você usar esse construtor, não vai precisa estender o
View.DragShadowBuildernem substituir os métodos dele. Por padrão, você recebe uma sombra de arrastar com a mesma aparência daViewque é transmitida como argumento, centralizada no local em que o usuário toca na tela.View.DragShadowBuilder()Se você usar esse construtor, nenhum objeto
Viewestará disponível no objetoView.DragShadowBuilder. O campo está definido comonull. EstendaView.DragShadowBuildere substitua os métodos. Caso contrário, você vai ter uma ação de arrastar invisível. O sistema não gera um erro.
A classe View.DragShadowBuilder tem dois métodos que, juntos, criam a ação de arrastar
e soltar:
onProvideShadowMetrics()O sistema chama esse método imediatamente após
startDragAndDrop()ser chamado. Use o método para enviar as dimensões e o ponto de contato da ação de arrastar ao sistema. O método tem dois parâmetros:outShadowSize:um objetoPoint. A largura da sombra de ação de arrastar aparece emx, e a altura aparece emy.outShadowTouchPoint:um objetoPoint. O ponto de contato é a área dentro da sombra de arrastar que precisa estar sob o dedo do usuário durante a ação de arrastar. A posição X aparece emx, e a posição Y aparece emy.onDrawShadow()Imediatamente após a chamada do método
onProvideShadowMetrics(), o sistema chamaonDrawShadow()para criar a ação de arrastar. O método tem um único argumento, um objetoCanvasque o sistema cria dos parâmetros fornecidos emonProvideShadowMetrics(). O método exibe a ação de arrastar naCanvasfornecida.
Para melhorar a performance, use um tamanho pequeno para a ação de arrastar. Para um único item, recomendamos usar um ícone. Para uma seleção múltipla, recomendamos usar ícones em uma pilha em vez de imagens completas espalhadas pela tela.
Listeners de eventos de arrastar e métodos de callback
Uma View recebe eventos de arrastar com um listener de eventos de arrastar que implementa
View.OnDragListener ou com o método de callback onDragEvent() da visualização. Quando
o sistema chama o método ou listener, ele fornece um argumento
DragEvent.
Na maioria dos casos, é preferível usar um listener que um método de callback. Ao
projetar IUs, você normalmente não cria subclasses de View, mas usar o
método de callback força a criação de subclasses para substituir o método. Por
comparação, você pode implementar uma classe de listener e a usar com vários
objetos View diferentes. Também é possível implementá-la como uma classe in-line anônima
ou uma expressão lambda. Para definir o listener de um objeto View, chame o método
setOnDragListener().
Como alternativa, é possível alterar a implementação padrão de onDragEvent()
sem substituir o método. Defina um
OnReceiveContentListener
em uma visualização. Para mais detalhes, consulte
setOnReceiveContentListener().
Por padrão, o método onDragEvent() faz o seguinte:
- Retorna "true" em resposta à chamada para
startDragAndDrop(). Chama
performReceiveContent()se os dados de arrastar e soltar forem soltos na visualização. Os dados são transmitidos para o método como um objetoContentInfo. O método invoca oOnReceiveContentListener.Retorna verdadeiro se os dados de arrastar e soltar forem soltos na visualização e o
OnReceiveContentListenerconsumir qualquer conteúdo.
Defina o OnReceiveContentListener para processar os dados específicos do seu app. Se quiser oferecer compatibilidade com versões anteriores até o nível da API 24, use a versão do OnReceiveContentListener do Jetpack.
Você pode ter um listener de eventos de arrastar e um método de callback para um objeto View. Nesse caso, o sistema chama o listener primeiro. O sistema não chama o
método de callback, a menos que o listener retorne false.
A combinação dos métodos onDragEvent() e View.OnDragListener é
análoga à combinação de
onTouchEvent()
e View.OnTouchListener
usados com eventos de toque.