As seções a seguir explicam alguns dos principais conceitos do processo de arrastar e soltar.
Processo de arrastar e soltar
Há quatro etapas ou estados no processo de arrastar e soltar: iniciado, continuo, solto e encerrado.
- Iniciada
Em resposta ao gesto de arrastar de um usuário, seu app chama
startDragAndDrop()
para instruir o sistema a iniciar uma operação de arrastar e soltar. Os argumentos do método fornecem o seguinte:- 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 receber uma sombra da ação de arrastar. Em seguida, o sistema mostra a ação de arrastar no dispositivo.
- Em seguida, o sistema envia um evento de arrastar com o tipo de ação
ACTION_DRAG_STARTED
para o listener de eventos de arrastar de todos os objetosView
no layout atual. Para continuar recebendo eventos de arrastar, incluindo um possível evento de soltar, o listener de eventos de arrastar precisa retornartrue
. Isso registra o listener no sistema. Somente listeners registrados continuam recebendo eventos de arrastar. Nesse ponto, os listeners também podem mudar a aparência do objetoView
de 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 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 não está interessado na operação de arrastar e soltar e não quer aceitar os dados arrastados.
- Em andamento
- O usuário continua a arrastar. À medida que a sombra da 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
View
em resposta ao evento. Por exemplo, se o evento indicar que a sombra de arraste entra na caixa delimitadora do destino de soltar (tipo de açãoACTION_DRAG_ENTERED
), o listener pode reagir destacando oView
. - Solto
- O usuário libera a sombra de arraste 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 transmitidos ao sistema na chamada parastartDragAndDrop()
que inicia a operação. Espera-se que o listener retorne o booleanotrue
ao sistema se ele processar os dados descartados com êxito. : esta etapa ocorre apenas quando o usuário solta a sombra da ação de arrastar dentro da caixa delimitadora de umaView
com um listener registrado para receber eventos de arrastar (um destino de soltar). Se o usuário soltar a sombra da ação de arrastar em qualquer outra situação, nenhum evento de arrastarACTION_DROP
será enviado. - Finalizado
Depois que o usuário soltar a sombra da ação de arrastar e depois que o sistema enviar
um evento de arrastar com o tipo de ação
ACTION_DROP
. Se necessário, o sistema enviará um evento de arrastar com o tipo de açãoACTION_DRAG_ENDED
para indicar que a operação de arrastar e soltar acabou. Isso será feito independentemente de onde o usuário solte a sombra de arraste. O evento é enviado para todos os listeners registrados para receber eventos de arrastar, mesmo que o listener também receba 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:
Tipo de ação | Significado |
---|---|
ACTION_DRAG_STARTED |
O aplicativo chama startDragAndDrop() e extrai
uma sombra da ação de arrastar. Se o listener quiser continuar recebendo eventos de arrastar
para essa operação, será necessário retornar o booleano true ao
sistema.
|
ACTION_DRAG_ENTERED |
A sombra de arraste 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 sombra da ação de arrastar entra na caixa delimitadora.
|
ACTION_DRAG_LOCATION |
Depois de um
evento ACTION_DRAG_ENTERED , a sombra da ação de arrastar ainda
está dentro da caixa delimitadora da View do listener de eventos
de arrastar.
|
ACTION_DRAG_EXITED |
Após um ACTION_DRAG_ENTERED e pelo menos um
evento ACTION_DRAG_LOCATION , a sombra de arraste se move
para fora da caixa delimitadora da View do listener de eventos
de arrastar.
|
ACTION_DROP |
A sombra de arraste é liberada sobre o 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 booleano
true em 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 sobre uma View
cujo listener não está registrado ou se o usuário liberar a sombra
de arrastar sobre qualquer elemento que não faça parte do layout atual.
O listener retornará 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
açã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() retornará false .
|
O objeto DragEvent
também contém os dados e metadados que o aplicativo fornece ao sistema na chamada para 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 a eles, consulte a seção Uma
operação de arrastar e soltar.
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 mostra 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 sombra de arrastar. Você pode criá-la com os métodos declarados 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 definidos em
View.DragShadowBuilder
para ter uma sombra da ação de arrastar.
A classe View.DragShadowBuilder
tem dois construtores:
View.DragShadowBuilder(View)
Esse construtor aceita todos os objetos
View
do aplicativo. O construtor armazena o objetoView
no objetoView.DragShadowBuilder
para que os callbacks possam o acessar a fim de construir a ação de arrastar. A visualização não precisa ser umaView
selecionada pelo usuário para iniciar a operação de arrastar.Se você usar esse construtor, não vai precisa estender o
View.DragShadowBuilder
nem substituir os métodos dele. Por padrão, você tem uma sombra de arraste com a mesma aparência que aView
transmitida como argumento, centralizada no local em que o usuário toca na tela.View.DragShadowBuilder()
Se você usar esse construtor, nenhum objeto
View
vai estar disponível no objetoView.DragShadowBuilder
. O campo está definido comonull
. EstendaView.DragShadowBuilder
e substitua os métodos. Caso contrário, uma ação de arrastar invisível vai aparecer. O sistema não gera um erro.
A classe View.DragShadowBuilder
tem dois métodos que, juntos, criam a sombra
da ação de arrastar:
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 arraste fica emx
, e a altura emy
.outShadowTouchPoint
:um objetoPoint
. O ponto de contato é o local dentro da sombra da ação de arrastar que precisa estar sob o dedo do usuário durante a ação. A posição X aparece emx
, e a posição Y, 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 objetoCanvas
que o sistema cria usando os parâmetros fornecidos emonProvideShadowMetrics()
. O método desenha a sombra da ação de arrastar noCanvas
fornecido.
Para melhorar o desempenho, mantenha o tamanho da sombra da ação de arrastar pequeno. Para um único item, você pode usar um ícone. Para uma seleção de vários itens, convém usar ícones em uma pilha em vez de imagens completas espalhadas pela tela.
Listeners de eventos de arrastar e métodos de callback
Um 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. Você também pode implementá-la como uma classe in-line anônima
ou expressão lambda. Se quiser definir o listener de um objeto View
, chame
setOnDragListener()
.
Como alternativa, você pode mudar 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 verdadeiro em resposta à chamada para
startDragAndDrop()
. Chamar
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
OnReceiveContentListener
consumir qualquer conteúdo.
Defina o OnReceiveContentListener
para processar os dados especificamente para seu
app. Para compatibilidade com versões anteriores até o nível 24 da API, use a versão de
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 do método onDragEvent()
e View.OnDragListener
é
análoga à combinação de
onTouchEvent()
e View.OnTouchListener
usados com eventos de toque.