Efecto Glass de iOS 26 con Compatibilidad Retroactiva en SwiftUI
Introducción
iOS 26 introdujo Liquid Glass, la evolución de diseño más significativa de Apple desde iOS 7. Este material translúcido y dinámico refleja y refracta el contenido circundante, creando un efecto visual sofisticado para elementos de navegación y controles.
Aunque el nuevo modificador .glassEffect() hace que implementar este diseño sea sencillo, la mayoría de las apps aún necesitan soportar versiones anteriores de iOS. Este artículo te muestra cómo crear una extensión de View reutilizable que usa Liquid Glass nativo en iOS 26+ y hace fallback a .thinMaterial en versiones anteriores.
El Desafío
Cuando intentas usar .glassEffect() en versiones de iOS anteriores a la 26, tu app no compila. Necesitas una solución que:
- Use Liquid Glass nativo en iOS 26+
- Proporcione un fallback consistente para iOS 18-25
- Mantenga tu código de vista limpio y simple
La Solución
Aquí hay una extensión de View que maneja ambos casos de forma elegante:
import SwiftUI
extension View {
/// Aplica un efecto glass con compatibilidad hacia adelante.
/// - En iOS 26+: Usa `.glassEffect()` nativo para apariencia liquid glass
/// - En iOS 18-25: Hace fallback a `.thinMaterial` para consistencia
@ViewBuilder
func glassedEffect(in shape: some Shape, interactive: Bool = false) -> some View {
if #available(iOS 26.0, *) {
self.glassEffect(interactive ? .regular.interactive() : .regular, in: shape)
.clipShape(shape)
} else {
background {
shape.fill(.thinMaterial)
}
.clipShape(shape)
}
}
}Cómo Funciona
Analicemos los componentes clave:
1. El Atributo @ViewBuilder
El atributo @ViewBuilder permite que la función retorne diferentes tipos de vista dependiendo de la versión de iOS. Sin él, Swift requeriría que ambas ramas retornaran el mismo tipo.
2. Verificación de Disponibilidad
if #available(iOS 26.0, *) {Esta verificación en tiempo de compilación asegura que el código de Liquid Glass solo se ejecute en iOS 26+. El compilador sabe que esto es seguro y permite el modificador .glassEffect() en esa rama.
3. Liquid Glass Nativo (iOS 26+)
self.glassEffect(interactive ? .regular.interactive() : .regular, in: shape)
.clipShape(shape)En iOS 26+, usamos el modificador nativo con:
- Variante
.regularpara apariencia glass estándar .interactive()para controles que deben responder al toque con efectos de escala y brillo- El parámetro shape controla el límite del glass
4. Fallback Material (iOS 18-25)
background {
shape.fill(.thinMaterial)
}
.clipShape(shape)Para versiones anteriores, .thinMaterial proporciona un efecto translúcido similar que combina bien con el diseño del sistema.
Ejemplos de Uso
Botón Básico con Efecto Glass
Button("Agregar Elemento") {
// acción
}
.padding()
.glassedEffect(in: Capsule())Botón de Acción Flotante Interactivo
Button(action: agregarElemento) {
HStack(spacing: 8) {
Image(systemName: "plus")
.font(.system(size: 20, weight: .semibold))
Text("Agregar Nivel")
}
.foregroundStyle(Color.primary)
.padding(.horizontal, 20)
.frame(height: 58)
.glassedEffect(in: Capsule(), interactive: true)
.shadow(color: Color.black.opacity(0.12), radius: 12, y: 8)
}Tarjeta con Esquinas Redondeadas
VStack(alignment: .leading) {
Text("Estadísticas")
.font(.headline)
Text("Tu resumen semanal")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.padding()
.glassedEffect(in: RoundedRectangle(cornerRadius: 16))Botón de Ícono Circular
Button(action: mostrarConfiguracion) {
Image(systemName: "gear")
.font(.title2)
.frame(width: 44, height: 44)
.glassedEffect(in: Circle(), interactive: true)
}Consideraciones de Diseño
Cuándo Usar Efectos Glass
Según las guías de diseño de Apple, Liquid Glass debe reservarse para la capa de navegación, no para el contenido principal. Piensa en toolbars, botones de acción flotantes y overlays de control.
Evita Anidar Glass
Glass no puede muestrear otros elementos glass. Si tienes múltiples elementos glass cerca unos de otros, envuélvelos en un GlassEffectContainer en iOS 26+ para asegurar un comportamiento visual consistente.
Extendiendo para Más Opciones
Puedes expandir la extensión para soportar más variantes de glass:
extension View {
@ViewBuilder
func glassedEffect(
in shape: some Shape,
variant: GlassVariant = .regular,
interactive: Bool = false
) -> some View {
if #available(iOS 26.0, *) {
let glass: Glass = switch variant {
case .regular: .regular
case .clear: .clear
}
self.glassEffect(interactive ? glass.interactive() : glass, in: shape)
.clipShape(shape)
} else {
background {
shape.fill(.thinMaterial)
}
.clipShape(shape)
}
}
}
enum GlassVariant {
case regular
case clear
}Conclusión
Soportar el Liquid Glass de iOS 26 mientras se mantiene compatibilidad retroactiva no requiere abstracciones complejas. Una simple extensión de View con @ViewBuilder y verificaciones #available te da lo mejor de ambos mundos: Liquid Glass nativo en dispositivos más nuevos y un fallback elegante de material en dispositivos más antiguos.
Este patrón mantiene tu código de vista limpio—solo llama .glassedEffect(in: Capsule()) y deja que la extensión se encargue del resto.

