Introducción
SwiftUI ha revolucionado el desarrollo de aplicaciones para el ecosistema Apple gracias a su enfoque declarativo, su sintaxis limpia y su integración profunda con Xcode. Entre sus componentes más utilizados se encuentra TabView, una vista fundamental para construir interfaces basadas en pestañas, muy común en apps de iOS como redes sociales, reproductores multimedia, aplicaciones bancarias o plataformas educativas.
Por defecto, cuando utilizamos TabView con el estilo .page o incluso con el estilo de pestañas tradicional, SwiftUI habilita un gesto de deslizamiento (swipe) que permite al usuario cambiar de pestaña arrastrando la pantalla de izquierda a derecha o viceversa. Aunque esto es conveniente en muchos casos, hay situaciones donde este comportamiento no es deseable.
En este tutorial aprenderás, paso a paso, cómo desactivar el gesto de swipe en un TabView usando SwiftUI y Xcode, explorando diferentes enfoques, desde soluciones simples hasta técnicas más avanzadas utilizando UIKit cuando es necesario.
¿Por qué querrías desactivar el swipe en un TabView?
Antes de entrar en código, veamos algunos casos reales donde bloquear el gesto de swipe es una buena idea:
- Flujos guiados
Si tu app presenta un proceso paso a paso (onboarding, tutorial, registro), no quieres que el usuario salte de una pestaña a otra sin seguir el flujo correcto. - Evitar conflictos de gestos
Si una de las vistas contiene unScrollView, un mapa o un carrusel, el gesto de swipe puede interferir con la navegación entre pestañas. - Control de navegación
Puede que solo quieras permitir el cambio de pestaña mediante botones, validaciones o lógica específica. - Apps educativas o de exámenes
En apps de cuestionarios o evaluaciones, permitir que el usuario navegue libremente entre pestañas podría romper la lógica de la aplicación.
Cómo funciona TabView internamente
En SwiftUI, TabView es una abstracción que, en iOS, se apoya internamente en componentes de UIKit:
- Para el estilo clásico de pestañas:
UITabBarController - Para el estilo
.page:UIPageViewControllero unUIScrollView
Esto es importante porque el gesto de swipe está gestionado por estos componentes internos, no directamente por SwiftUI.
SwiftUI no proporciona actualmente una propiedad oficial como:
TabView {
...
}.disableSwipe(true) // ❌ No existePor eso debemos recurrir a técnicas alternativas.
Ejemplo base: TabView con swipe activo
Empezamos con un ejemplo básico para entender el comportamiento por defecto:
struct ContentView: View {
var body: some View {
TabView {
Text("Pantalla 1")
.font(.largeTitle)
.tabItem {
Label("Uno", systemImage: "1.circle")
}
Text("Pantalla 2")
.font(.largeTitle)
.tabItem {
Label("Dos", systemImage: "2.circle")
}
Text("Pantalla 3")
.font(.largeTitle)
.tabItem {
Label("Tres", systemImage: "3.circle")
}
}
}
}Con esto, el usuario puede cambiar de pestaña tocando la TabBar o deslizando horizontalmente.
Nuestro objetivo es bloquear el gesto de deslizamiento.
Solución 1: Usar TabView con selección controlada
Una forma sencilla de evitar cambios de pestaña no deseados es controlar la selección con una variable @State.
struct ContentView: View {
@State private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
Text("Pantalla 1")
.tag(0)
Text("Pantalla 2")
.tag(1)
Text("Pantalla 3")
.tag(2)
}
}
}Esto por sí solo no desactiva el swipe, pero nos permite saber cuándo el usuario intenta cambiar de pestaña.
Podemos usar esto para revertir el cambio:
.onChange(of: selectedTab) { newValue in
selectedTab = 0 // Siempre vuelve a la pestaña 0
}Esto crea la ilusión de que el swipe no funciona, pero la animación ocurre brevemente. No es ideal, pero puede servir en casos simples.
Solución 2: Usar .page y bloquear el gesto
Cuando TabView se usa con .tabViewStyle(.page), SwiftUI usa un UIScrollView por debajo.
TabView {
Color.red
Color.green
Color.blue
}
.tabViewStyle(.page)Aquí el swipe es aún más evidente.
La clave es desactivar el scroll del UIScrollView interno.
Para ello necesitamos usar UIKit mediante un UIViewRepresentable.
Creando un helper para desactivar el scroll
Creamos una vista invisible que busque el UIScrollView padre y desactive su scroll:
import SwiftUI
struct DisableSwipeTabView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async {
if let scrollView = view.findScrollView() {
scrollView.isScrollEnabled = false
}
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}Y un helper para buscar el UIScrollView:
extension UIView {
func findScrollView() -> UIScrollView? {
if let scroll = self.superview as? UIScrollView {
return scroll
}
for view in self.subviews {
if let found = view.findScrollView() {
return found
}
}
return nil
}
}Aplicándolo al TabView
Ahora lo añadimos dentro del TabView:
struct ContentView: View {
var body: some View {
TabView {
Text("Página 1")
Text("Página 2")
Text("Página 3")
}
.tabViewStyle(.page)
.overlay(DisableSwipeTabView())
}
}Resultado:
- Las páginas siguen existiendo
- El gesto de swipe queda completamente bloqueado
- Puedes controlar la navegación con botones
Añadiendo navegación por botones
Ahora creamos navegación manual:
struct ContentView: View {
@State private var index = 0
var body: some View {
VStack {
TabView(selection: $index) {
Text("Paso 1").tag(0)
Text("Paso 2").tag(1)
Text("Paso 3").tag(2)
}
.tabViewStyle(.page)
.overlay(DisableSwipeTabView())
HStack {
Button("Anterior") {
if index > 0 { index -= 1 }
}
Button("Siguiente") {
if index < 2 { index += 1 }
}
}
}
}
}Ahora tienes un sistema de páginas sin swipe.
Ventajas de este enfoque
- Control total de la navegación
- No hay animaciones de swipe no deseadas
- Compatible con iOS moderno
- Ideal para onboarding, formularios o flujos guiados
Posibles problemas
- Cambios internos de SwiftUI
Apple puede cambiar la estructura interna delTabView. - Uso de UIKit
Aunque SwiftUI es declarativo, algunas soluciones aún requieren UIKit. - Testing
Debes probar en varios dispositivos.
Casos de uso reales
- Onboarding de apps
- Tutoriales interactivos
- Apps de cursos
- Formularios multipaso
- Juegos por niveles
Conclusión
Desactivar el gesto de swipe en un TabView en SwiftUI no es algo que Apple proporcione directamente, pero con un poco de creatividad y entendiendo cómo funciona SwiftUI internamente, podemos lograr un control total de la navegación.
Usando un pequeño puente hacia UIKit, podemos desactivar el UIScrollView que SwiftUI utiliza internamente y crear experiencias mucho más controladas, profesionales y adaptadas a nuestras necesidades.
Si estás construyendo una app en Xcode donde el flujo de navegación debe ser preciso, esta técnica te permitirá elevar la calidad de tu interfaz y evitar comportamientos no deseados.
Si tienes cualquier duda sobre este artículo, contacta conmigo y estaré encantado de ayudarte 🙂. Puedes contactar conmigo en mi perfil de X o en mi perfil de Instagram










