Principais pontos
Deslize é um movimento rápido e deslizante do dedo sobre a superfície da tela, terminando com a remoção do dedo. Um deslize pode ser curto (passar um elemento) ou longo (abrir uma cortina), mas a principal característica é a discrição: o sistema o reconhece como um único evento, não como uma sequência contínua de coordenadas.
Os sistemas operacionais móveis detectam um deslize com base em três parâmetros: distância mínima (limiar), velocidade mínima (velocity) e direção. Se o dedo se move lentamente ou a distância é insuficiente, o sistema interpreta o gesto como panorâmica ou toque. Os valores de limiar diferem entre plataformas: o iOS usa uma constante no UISwipeGestureRecognizer com um limiar fixo, o Android usa ViewConfiguration.getScaledTouchSlop(), que retorna ~8–16 dp dependendo da densidade da tela.
De acordo com a Documentação para desenvolvedores Android, onFling (swipe) no GestureDetector é acionado em velocidades acima de 100 px/s e distâncias a partir de 50px. Na IT Sectr, usamos deslize para navegação (galerias, interfaces de cartão, integração) — este gesto é intuitivo para usuários de todas as idades.
Deslize e panorâmica (pan/drag) são tipos diferentes de gestos, embora ambos envolvam mover o dedo pela tela. O deslize é discreto e significa "realizar uma ação", enquanto a panorâmica é contínua e significa "mover um objeto enquanto o dedo estiver na tela".
| Parâmetro | Swipe | Pan/Drag |
|---|---|---|
| Tipo | Discreto | Contínuo |
| Eventos | Único (reconhecido/não reconhecido) | Múltiplos (.began → .changed → .ended) |
| Velocidade | Alta (movimento rápido) | Qualquer (movimento lento) |
| Exemplo iOS | UISwipeGestureRecognizer | UIPanGestureRecognizer |
| Exemplo Android | GestureDetector.onFling() | GestureDetector.onScroll() |
| Cenário | Excluir e-mail, virar página | Mover mapa, arrastar arquivo |
| Rastreamento de coordenadas | Não (apenas direção) | Sim (atualização constante de coordenadas) |
A escolha entre deslize e panorâmica depende da tarefa. Para ações em um elemento (excluir, arquivar, abrir menu) use deslize. Para manipulação direta (mover, dimensionar) use panorâmica. Misturar gestos no mesmo elemento requer require(toFail:) ou lógica personalizada.
UISwipeGestureRecognizer é uma subclasse de UIGestureRecognizer que reconhece um deslize discreto em uma das quatro direções. Ao contrário do UIPanGestureRecognizer, ele não gera eventos .changed intermediários: quando reconhecido, a ação é chamada exatamente uma vez.
A propriedade direction (UISwipeGestureRecognizer.Direction) define a direção rastreada — .left, .right, .up, .down. As direções podem ser combinadas usando uma máscara: [.left, .right] para deslizes horizontais. A propriedade numberOfTouchesRequired determina o número de dedos — 1 por padrão. O UISwipeGestureRecognizer não tem um limite de distância configurável — o iOS usa um valor interno de cerca de 20px, suficiente para reconhecimento confiável.
Como o UISwipeGestureRecognizer é um reconhecedor discreto, ele não entra em conflito com o UIPanGestureRecognizer: movimento lento aciona pan, movimento rápido aciona swipe. No entanto, ao coexistir com UITapGestureRecognizer na mesma view, pode ser necessário require(toFail:) para evitar reconhecimento falso de toque.
No Android, a principal API para reconhecimento de deslize é GestureDetector com o callback OnGestureListener, especificamente o método onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY). O GestureDetector analisa a posição inicial e final do dedo, a velocidade do movimento nos eixos e a distância, e então chama onFling quando os limiares são excedidos.
Os limiares mínimos são configuráveis via ViewConfiguration: VelocityTracker.getMinVelocity() (~100 px/s) e ViewConfiguration.getScaledTouchSlop() (~8–16 dp). Um OnSwipeTouchListener personalizado é um padrão comum que simplifica a API: o desenvolvedor não precisa calcular manualmente a direção e a velocidade. A Android Support Library não inclui um "SwipeDetector" interno, portanto um wrapper personalizado é a solução padrão.
Para deslizar em listas, o Google recomenda usar ItemTouchHelper.SimpleCallback do RecyclerView, que abstrai a detecção de gestos, animação e callbacks onSwiped(). Na IT Sectr, usamos um SwipeListener personalizado para ViewPager2 e interfaces de cartão — isso dá controle sobre a sensibilidade do deslize sem sacrificar o desempenho.
Para listas (UITableView, RecyclerView), Apple e Google fornecem APIs especializadas que substituem a adição manual de UISwipeGestureRecognizer. Essas APIs suportam botões de ação, animação personalizada e gestos "deslizar para excluir" — padrões comuns em aplicativos móveis.
No iOS (11+), usa-se UISwipeActionsConfiguration: o método tableView(_:leadingSwipeActionsConfigurationForRowAt:) retorna um array de UIContextualAction — botões com título, estilo (destructive, normal) e manipulador. Por exemplo, "Excluir" — .destructive com fundo vermelho, "Arquivar" — .normal com fundo cinza. O sistema anima o aparecimento dos botões e chama o bloco completion após um toque.
No Android, ItemTouchHelper.SimpleCallback é anexado ao RecyclerView via ItemTouchHelper.attachToRecyclerView(). Os parâmetros incluem flags de direção (start, end, up, down) e o callback onSwiped(viewHolder, direction). Dentro de onSwiped, adapter.notifyItemRemoved(position) é chamado para remover o item com animação. O ItemTouchHelper gerencia automaticamente gestos, conflitos de rolagem e retorno do item se o deslize não for concluído. De acordo com o Google I/O 2024, o ItemTouchHelper é usado em 70% dos aplicativos Android com ações de deslize em listas.
Adiciona UISwipeGestureRecognizer a uma view para retornar à tela anterior. O código mostra a configuração mínima do reconhecedor com a direção .left.
import UIKit
class CardViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swipeLeft = UISwipeGestureRecognizer(
target: self,
action: #selector(handleSwipeLeft(_:))
)
swipeLeft.direction = .left
swipeLeft.numberOfTouchesRequired = 1
view.addGestureRecognizer(swipeLeft)
}
@objc private func handleSwipeLeft(_: UISwipeGestureRecognizer) {
guard let nav = navigationController else { return }
if nav.viewControllers.count > 1 {
nav.popViewController(animated: true)
} else {
nav.dismiss(animated: true)
}
}
}
O reconhecedor é anexado à view raiz do controlador. A verificação navigationController.viewControllers.count garante que pop só seja executado quando houver uma tela anterior na pilha. Para controladores modais, usa-se dismiss. O código não requer verificação de estado — UISwipeGestureRecognizer é discreto e chama a ação apenas após reconhecimento bem-sucedido.
Implementa um wrapper simples do GestureDetector que determina a direção do deslize e chama os callbacks onSwipeLeft/Right.
import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
open class OnSwipeTouchListener(context: Context) : View.OnTouchListener {
private val gestureDetector = GestureDetector(context, GestureListener())
override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
companion object {
private const val SWIPE_THRESHOLD = 100
private const val SWIPE_VELOCITY_THRESHOLD = 100
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val diffX = e2.x - e1!!.x
val diffY = e2.y - e1.y
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD
&& Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD
) {
if (diffX > 0) onSwipeRight()
else onSwipeLeft()
return true
}
} else {
if (Math.abs(diffY) > SWIPE_THRESHOLD
&& Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD
) {
if (diffY > 0) onSwipeDown()
else onSwipeUp()
return true
}
}
return false
}
}
open fun onSwipeLeft() {}
open fun onSwipeRight() {}
open fun onSwipeUp() {}
open fun onSwipeDown() {}
}
OnSwipeTouchListener estende SimpleOnGestureListener, implementando onFling. diffX/diffY determinam a direção, SWIPE_THRESHOLD (100px) e SWIPE_VELOCITY_THRESHOLD (100 px/s) são os limiares. Uso: view.setOnTouchListener(OnSwipeTouchListener(context).apply { onSwipeLeft = { dismiss() } }).
Adiciona um botão de excluir ao deslizar para a esquerda em uma célula de tabela. Usa a API integrada do iOS 11+ sem reconhecimento manual de gestos.
func tableView(
_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(
style: .destructive,
title: "Excluir"
) { _, _, completionHandler in
items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
completionHandler(true)
}
deleteAction.backgroundColor = .systemRed
let config = UISwipeActionsConfiguration(actions: [deleteAction])
config.performsFirstActionWithFullSwipe = true
return config
}
O método retorna UISwipeActionsConfiguration com um array de UIContextualAction. style: .destructive define automaticamente o fundo vermelho. performsFirstActionWithFullSwipe = true permite executar a ação com um deslize completo sem toque adicional. Na IT Sectr, usamos esta API para todas as listas com ações — é padronizada, suporta VoiceOver e não requer GestureRecognizers personalizados.
Perguntas frequentes
O deslize é um gesto discreto com movimento rápido e remoção do dedo, a panorâmica é um arrasto contínuo com rastreamento de coordenadas. UISwipeGestureRecognizer é acionado uma vez, UIPanGestureRecognizer gera .began → .changed → .ended. A escolha depende do cenário: deslize para ações (excluir, virar), pan para movimento (mapa, controle deslizante).
A lógica do gesto é idêntica, mas a API difere. O iOS usa UISwipeGestureRecognizer com direction. O Android usa GestureDetector.onFling() com limiares personalizados. O resultado é o mesmo UX com implementações diferentes. Frameworks multiplataforma (Flutter, React Native) abstraem a diferença através de uma API de deslize unificada.
No iOS (11+), use UISwipeActionsConfiguration no UITableViewDelegate. No Android, use ItemTouchHelper.SimpleCallback para RecyclerView. Essas APIs substituem GestureRecognizers manuais, suportam botões de ação e animação, lidam corretamente com conflitos de rolagem e se adaptam às HIGs da plataforma.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também