Apresentação Modal é uma forma de exibir uma tela sobre o contexto atual, bloqueando a interação com a interface anterior. No desenvolvimento móvel, janelas modais são usadas para tarefas focadas: entrada de dados, confirmação de ações, autorização e seleção de opções. De acordo com Apple HIG, 2025, apresentações modais não devem ocupar mais de 20% dos cenários de navegação em um aplicativo. No Android, a modalidade é implementada através de DialogFragment, BottomSheet e Activity com flags de inicialização específicos.
Pontos principais
Apresentação Modal é um padrão de navegação onde uma nova tela aparece sobre a atual, bloqueando temporariamente a interação com o conteúdo pai. O usuário deve completar explicitamente a tarefa modal (cancelar, salvar, fechar) para retornar ao estado anterior.
A modalidade resolve uma tarefa cognitiva: ela foca a atenção do usuário em uma única ação sem distração do resto da interface. Isso é criticamente importante para formulários de registro, diálogos de confirmação, seleção de arquivos e autorização através de serviços de terceiros. As Human Interface Guidelines da Apple recomendam usar modalidade apenas para tarefas que exigem conclusão antes de prosseguir.
Ao contrário das janelas modais web, a Apresentação Modal móvel pode ser em tela cheia (ocupando toda a tela) ou parcial (Page Sheet, Bottom Sheet). A escolha do tipo depende do contexto da tarefa e das convenções da plataforma. iOS tende a usar Page Sheet para a maioria dos cenários, deixando Full Screen para players de vídeo e editores de foto.
Push Presentation (navegação por pilha) adiciona uma tela à pilha de navegação e mostra automaticamente um botão de voltar. O usuário pode retornar à tela anterior a qualquer momento. Apresentação Modal, ao contrário, exige conclusão explícita: o botão de voltar está ausente ou fecha a janela modal em vez de retornar à tela anterior.
As principais diferenças entre apresentação modal e push: Apresentação Modal bloqueia a navegação para trás sem perda de dados, requer uma ação para fechar (Save, Cancel, Done) e geralmente representa uma tarefa separada. Push Presentation preserva a hierarquia de navegação, adiciona automaticamente um botão de voltar e é adequado para visualização sequencial de conteúdo.
| Característica | Apresentação Modal | Push Presentation |
|---|---|---|
| Bloqueio de retorno | Sim, requer ação explícita | Não, botão de voltar sempre disponível |
| Uso típico | Formulários, autorização, seleção | Visualização detalhada, navegação |
| Animação | De baixo para cima (iOS), deslizar (Android) | Da direita para a esquerda (iOS) |
| Pilha de navegação | Não adicionada à pilha principal | Adicionada à pilha |
Na prática, a escolha entre Modal e Push depende do contexto. É recomendado usar modalidade para tarefas que o usuário deve completar antes de continuar, e Push para exploração sequencial de conteúdo. Misturar padrões na mesma tela causa confusão e degrada a UX.
iOS oferece vários estilos de apresentação modal através da enumeração UIModalPresentationStyle. UIKit suporta .fullScreen (tela cheia), .pageSheet (cartão com margem superior), .formSheet (janela centralizada no iPad) e .automatic (sistema escolhe baseado no contexto). Desde o iOS 13, o estilo padrão é .automatic, que seleciona .pageSheet para iPhone.
O método básico do UIKit para apresentação modal é present(_:animated:completion:). O controlador que chama o método se torna presentingViewController, e o novo se torna presentedViewController. O fechamento é feito através de dismiss(animated:completion:). SwiftUI fornece o modificador .sheet para comportamento similar.
A abordagem declarativa do SwiftUI usa os modificadores .sheet e .fullScreenCover. O primeiro cria um Page Sheet, o segundo cria uma apresentação modal em tela cheia. Ambos aceitam um binding a um Bool ou objeto identificável que controla a visibilidade da janela modal. O fechamento ocorre quando o binding é definido como false ou ao chamar dismiss do ambiente.
struct ContentView: View {
@State private var showModal = false
var body: some View {
Button("Abrir formulário") {
showModal = true
}
.sheet(isPresented: $showModal) {
RegistrationForm()
}
}
}
struct RegistrationForm: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
Button("Salvar") { dismiss() }
}
}
Android não tem uma única API para apresentação modal como o iOS. Em vez disso, a plataforma oferece vários mecanismos: DialogFragment para janelas de diálogo, BottomSheetDialogFragment para painéis inferiores e Activity com flags NEW_TASK e CLEAR_TOP para telas modais. Jetpack Compose introduziu um componente Dialog unificado para todos os tipos de janelas modais.
DialogFragment é a classe base para janelas modais no Android SDK. Ela gerencia o ciclo de vida do diálogo, lida com a rotação da tela e salva o estado. O fragmento é exibido sobre a Activity sem bloquear a pilha de navegação. O fechamento é feito através de dismiss() ou tocando fora da área do diálogo se setCancelable(true).
BottomSheetDialogFragment exibe uma janela modal como um painel que se eleva da parte inferior. Este padrão é popular no Material Design para seleção de opções, compartilhamento e ações rápidas. O BottomSheet pode ter altura fixa ou expansível (altura de visualização + altura total). No Compose, ModalBottomSheet da biblioteca Material3 é usado.
@Composable
fun ModalScreen(onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) {
Card(
modifier = Modifier.padding(16.dp)
) {
Column {
Text("Formulário modal", style = MaterialTheme.typography.headlineSmall)
Button(onClick = onDismiss) {
Text("Fechar")
}
}
}
}
}
Janelas modais são uma ferramenta poderosa de UX, mas seu uso excessivo degrada a experiência do usuário. Apple HIG e Google Material Design concordam nas recomendações: a modalidade deve ser usada para tarefas focadas e não deve exceder 20% do total de ações de navegação.
Janelas modais são adequadas para cenários: entrada de dados (formulários de registro, perfis), confirmação (exclusão, envio), seleção (seletor de data, gerenciador de arquivos) e autorização (OAuth, Firebase Auth). Se a tarefa leva menos de 30 segundos e requer bloqueio de contexto, escolha modalidade.
Não use apresentação modal para: visualização sequencial de conteúdo (use Push), exibição de erros (use Toast ou Snackbar), anúncios e ofertas promocionais sem solicitação explícita do usuário. Material Design recomenda evitar janelas modais aninhadas, pois isso desorienta o usuário e interrompe a hierarquia de navegação.
Para janelas modais com campos de texto, certifique-se de lidar com a perda de foco do teclado. Quando o teclado aparece, a janela modal deve se deslocar para cima para que o usuário veja o texto sendo digitado. UIKeyboardWillShowNotification no iOS e adjustResize no Android resolvem essa tarefa.
Vamos ver a implementação da apresentação modal em ambas as plataformas. O exemplo em Swift mostra a configuração de UIModalPresentationStyle.pageSheet com um delegado para lidar com o fechamento. O exemplo em Kotlin demonstra DialogFragment com um layout personalizado e preservação de estado.
let modalVC = ModalViewController()
modalVC.modalPresentationStyle = .pageSheet
if let sheet = modalVC.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersGrabberVisible = true
}
modalVC.presentationController?.delegate = self
present(modalVC, animated: true)
// MARK: - UIAdaptivePresentationControllerDelegate
extension ViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("Modal fechado")
}
}
class ModalDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_modal, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<Button>(R.id.closeButton).setOnClickListener {
dismiss()
}
}
}
Perguntas frequentes
Use Apresentação Modal para tarefas focadas que o usuário deve completar antes de continuar: formulários, confirmações, autorização. Push é adequado para visualização sequencial de conteúdo onde o usuário pode navegar livremente para trás. Uma janela modal não deve conter navegação dentro de si.
Desde o iOS 13, o estilo padrão .automatic seleciona .pageSheet para iPhone. .pageSheet é adequado para a maioria dos cenários (formulários, detalhes). .fullScreen é para conteúdo de mídia (vídeo, editores de foto). .formSheet é para aplicativos iPad que precisam de uma janela centralizada.
Jetpack Compose fornece o componente Dialog para janelas modais simples e ModalBottomSheet para painéis inferiores. Dialog aceita onDismissRequest e conteúdo no estilo Compose. Use rememberSaveable dentro do diálogo para preservação de estado.
Apple HIG e Material Design não recomendam janelas modais aninhadas. Se um usuário abre uma janela modal sobre outra janela modal, ele perde o contexto e pode ficar confuso sobre a hierarquia. Em vez de aninhar, use um Indicador de Etapa ou padrão de Assistente com uma única janela modal.
Use UIAdaptivePresentationControllerDelegate no iOS (método presentationControllerShouldDismiss) ou OnBackPressedDispatcher no Android. Quando houver alterações não salvas, mostre um AlertDialog com opções: salvar, descartar alterações ou permanecer na tela. Isso evita a perda acidental de dados pelo usuário.
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