Wilson Vargas

Liquid Glass, parte 2: adapta tu app .NET MAUI en vez de desactivarla

Con Xcode 27, Apple ignora UIDesignRequiresCompatibility y Liquid Glass es obligatorio. Cómo adaptar tu app .NET MAUI: barras, TitleView y vidrio en tus controles.

Liquid Glass, parte 2: adapta tu app .NET MAUI

¿Pusiste UIDesignRequiresCompatibility en tu Info.plist y te olvidaste del tema? Tengo malas noticias: ese truco tiene los días contados.

En febrero escribí cómo desactivar Liquid Glass en iOS 26 para ganar tiempo mientras adaptabas tu UI. En ese artículo dije que la opción iba a funcionar hasta iOS 27 y que desaparecería con iOS 28. El plazo resultó ser más corto: Con el SDK de iOS 27 (Xcode 27), el flag simplemente se ignora.

Así que toca hacer lo que ese artículo recomendaba al final: adaptar la app de verdad. En esta segunda parte te cuento qué cambió, qué adopta .NET MAUI solo, qué tienes que revisar tú y cómo aplicar el efecto de vidrio a tus propios controles.

¿Qué cambió?

En la WWDC de junio de 2026, junto con la beta de iOS 27, Apple actualizó la documentación de UIDesignRequiresCompatibility. Ahora dice que el sistema ignora esta clave cuando compilas para iOS 27, iPadOS 27, Mac Catalyst 27, macOS 27 o tvOS 27, o versiones posteriores.

En otras palabras: mientras compiles con Xcode 26 el flag sigue funcionando, pero el día que pases a Xcode 27, Liquid Glass se aplica sí o sí.

El calendario de Liquid Glass
Fecha Qué pasó Qué significa para ti
Sep 2025 iOS 26 y Xcode 26 traen Liquid Glass Puedes desactivarlo con UIDesignRequiresCompatibility.
Jun 2026 Beta de iOS 27 Apple anuncia que el flag se ignora con el SDK de iOS 27.
Sep 2026 iOS 27 y Xcode 27 estables Si compilas con Xcode 27, ya no hay forma de desactivarlo.
~Abr 2027 (estimado) App Store exige el SDK nuevo Normalmente Apple pide el SDK más reciente para subir apps unos meses después del lanzamiento.
Ojo: la fecha de abril de 2027 es una estimación basada en cómo Apple lo ha hecho en años anteriores; todavía no es oficial. Pero no esperes a que la anuncien para empezar.

Este es el código que puse en febrero, y que ya puedes ir preparándote para quitar:

<!-- Info.plist: funciona con Xcode 26, se IGNORA con Xcode 27 -->
<key>UIDesignRequiresCompatibility</key>
<true/>

La buena noticia: MAUI la tiene fácil

Aquí .NET MAUI tiene una ventaja enorme: usa los controles nativos de UIKit. NavigationPage y Shell usan una UINavigationBar real, y las pestañas usan una UITabBar real. Por eso, cuando compilas con el SDK de iOS 26, esas barras adoptan Liquid Glass automáticamente, sin que cambies una línea.

Lo que se rompe no es MAUI, es lo que tú le pusiste encima: colores sólidos, TitleView personalizados o renderers que tocan las barras.

Qué adopta Liquid Glass solo y qué revisas tú

Así se ve la diferencia en una app típica:

Tu app antes y después de Liquid Glass

Paso 1: audita tu app

Antes de cambiar nada, busca todo lo que pueda estar peleando con Liquid Glass. Este comando te da una lista rápida desde la raíz de tu proyecto:

grep -rnE "BarBackgroundColor|BarBackground=|BarTextColor|TabBarBackgroundColor|Shell\.(BackgroundColor|ForegroundColor|TitleColor)|TitleView|NavigationRenderer|TabbedRenderer|UINavigationBarAppearance|UITabBarAppearance" \
  --include=*.xaml --include=*.cs .

Y luego quita el flag en una rama y ejecuta la app en un simulador con iOS 26. Así ves hoy, con Xcode 26, exactamente lo que vas a ver cuando pases a Xcode 27.

Paso 2: deja que Liquid Glass se vea

El error más común es tener colores sólidos en las barras. En Liquid Glass las barras son translúcidas y el contenido pasa por debajo, así que un color sólido crea una "losa" opaca que tapa el efecto.

Si usas la plantilla de .NET MAUI, en Resources/Styles/Styles.xaml tienes algo así:

<Style TargetType="Shell" ApplyToDerivedTypes="True">
    <Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Gray950}}" />
    <Setter Property="Shell.ForegroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource SecondaryDarkText}}" />
    <Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource SecondaryDarkText}}" />
    <Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
    <!-- ... -->
</Style>

El problema no es solo el fondo: si quitas el color de la barra pero dejas el texto en blanco, en modo claro vas a tener texto blanco sobre vidrio claro. La solución es mantener tus colores en Android y dejar que iOS use los del sistema:

<Style TargetType="Shell" ApplyToDerivedTypes="True">
    <!-- En iOS no ponemos color: la barra usa Liquid Glass -->
    <Setter Property="Shell.BackgroundColor">
        <Setter.Value>
            <OnPlatform x:TypeArguments="Color">
                <On Platform="Android, WinUI" Value="{StaticResource Primary}" />
            </OnPlatform>
        </Setter.Value>
    </Setter>

    <!-- El texto también: en iOS lo decide el sistema según el fondo -->
    <Setter Property="Shell.ForegroundColor">
        <Setter.Value>
            <OnPlatform x:TypeArguments="Color">
                <On Platform="Android, WinUI" Value="{StaticResource White}" />
            </OnPlatform>
        </Setter.Value>
    </Setter>

    <Setter Property="Shell.TitleColor">
        <Setter.Value>
            <OnPlatform x:TypeArguments="Color">
                <On Platform="Android, WinUI" Value="{StaticResource White}" />
            </OnPlatform>
        </Setter.Value>
    </Setter>

    <!-- Y nada de fondo sólido en la barra de pestañas de iOS -->
    <Setter Property="Shell.TabBarBackgroundColor">
        <Setter.Value>
            <OnPlatform x:TypeArguments="Color">
                <On Platform="Android, WinUI" Value="{StaticResource White}" />
            </OnPlatform>
        </Setter.Value>
    </Setter>
</Style>

Como no hay un valor para iOS, OnPlatform devuelve el valor por defecto y la barra se queda con el estilo nativo. Si usas NavigationPage en vez de Shell, aplica la misma idea con BarBackgroundColor y BarTextColor.

Paso 3: cuidado con el TitleView

Si hay algo que da problemas con Liquid Glass, es el TitleView. En el repositorio de .NET MAUI hay varios issues abiertos por esto, por ejemplo:

A mí mismo me pasó con un TitleView en MAUI (lo muestro en la parte 1). Tienes dos caminos:

✅ Opción recomendada: usa Title y ToolbarItems. Es lo que Apple espera, y el sistema lo dibuja con el título grande y los botones de vidrio.

<ContentPage Title="Inicio">
    <ContentPage.ToolbarItems>
        <ToolbarItem IconImageSource="plus.png" Command="{Binding AddCommand}" />
        <!-- En .NET 11, los Secondary van a un menú de "más opciones" en la barra -->
        <ToolbarItem Text="Configuración" Order="Secondary" Command="{Binding SettingsCommand}" />
    </ContentPage.ToolbarItems>
</ContentPage>

✅ Si necesitas un encabezado muy personalizado: oculta la barra en iOS y dibuja tu encabezado como parte de la página. Es el workaround que sugieren en el issue #34610:

<ContentPage Shell.NavBarIsVisible="{OnPlatform iOS=False, Default=True}">
    <Grid RowDefinitions="Auto,*">
        <!-- Tu encabezado, solo en iOS -->
        <Grid Grid.Row="0"
              IsVisible="{OnPlatform iOS=True, Default=False}"
              Padding="20,8"
              ColumnDefinitions="*,Auto">
            <Label Text="Inicio" FontSize="32" FontAttributes="Bold" />
            <Button Grid.Column="1" Text="+" Command="{Binding AddCommand}" />
        </Grid>

        <CollectionView Grid.Row="1" ItemsSource="{Binding Items}" />
    </Grid>
</ContentPage>

❌ Evita: seguir metiendo layouts complejos dentro del TitleView esperando que se vean igual que antes.

Paso 4: aplica Liquid Glass a tus propios controles

Hasta aquí dejamos que el sistema haga su trabajo. Pero también puedes usar Liquid Glass en tus propias vistas, por ejemplo en un botón flotante. Antes de hacerlo, ten clara la regla principal de Apple:

El vidrio flota sobre el contenido

Liquid Glass es para la capa de navegación: barras, pestañas y controles que flotan sobre el contenido. Tus listas y tarjetas van en la capa de contenido, sin Liquid Glass.

iOS 26 trae dos APIs que puedes usar desde .NET:

API de iOS 26 En .NET Para qué sirve
Botones de vidrio UIButtonConfiguration.GlassButtonConfiguration y ProminentGlassButtonConfiguration Botones con el estilo de vidrio nativo.
Efecto de vidrio UIGlassEffect.Create(UIGlassEffectStyle.Regular) dentro de un UIVisualEffectView Poner vidrio detrás de cualquier vista.

Vamos a usar las dos con Mappers, sin crear un handler desde cero (si no conoces los Mappers, te los explico en el artículo sobre migrar Custom Renderers a Handlers).

Los controles

Dos subclases vacías (o casi) para limitar la personalización a los controles que queremos:

namespace MiApp.Controls;

public class GlassButton : Button
{
    public static readonly BindableProperty IsProminentProperty =
        BindableProperty.Create(nameof(IsProminent), typeof(bool), typeof(GlassButton), false);

    // Prominent = vidrio con el color de acento, para la acción principal
    public bool IsProminent
    {
        get => (bool)GetValue(IsProminentProperty);
        set => SetValue(IsProminentProperty, value);
    }
}

public class GlassCard : Border
{
}

Los Mappers

Los junto en una extensión para dejar MauiProgram.cs limpio:

using Microsoft.Maui.Handlers;
using MiApp.Controls;
#if IOS
using UIKit;
#endif

namespace MiApp;

public static class LiquidGlassExtensions
{
    public static MauiAppBuilder UseLiquidGlass(this MauiAppBuilder builder)
    {
#if IOS
        // Se ejecuta al crear el botón y cada vez que cambian Text o IsProminent
        ButtonHandler.Mapper.AppendToMapping(nameof(IText.Text), MapGlassButton);
        ButtonHandler.Mapper.AppendToMapping(nameof(GlassButton.IsProminent), MapGlassButton);

        BorderHandler.Mapper.AppendToMapping("GlassCard", MapGlassCard);
#endif
        return builder;
    }

#if IOS
    static void MapGlassButton(IButtonHandler handler, IButton view)
    {
        if (view is not GlassButton button || !OperatingSystem.IsIOSVersionAtLeast(26))
            return;

        var config = button.IsProminent
            ? UIButtonConfiguration.ProminentGlassButtonConfiguration
            : UIButtonConfiguration.GlassButtonConfiguration;

        config.Title = button.Text;
        handler.PlatformView.Configuration = config;
    }

    static void MapGlassCard(IBorderHandler handler, IBorderView view)
    {
        if (view is not GlassCard || !OperatingSystem.IsIOSVersionAtLeast(26))
            return;

        var container = handler.PlatformView;

        // El mapper puede ejecutarse más de una vez: no agregamos dos capas de vidrio
        if (container.Subviews.OfType<UIVisualEffectView>().Any())
            return;

        var glass = new UIVisualEffectView(UIGlassEffect.Create(UIGlassEffectStyle.Regular))
        {
            Frame = container.Bounds,
            AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight,
            UserInteractionEnabled = false
        };

        glass.Layer.CornerRadius = 24;
        glass.ClipsToBounds = true;

        container.InsertSubview(glass, 0);
    }
#endif
}

Y lo activas en MauiProgram.cs:

builder
    .UseMauiApp<App>()
    .UseLiquidGlass();

Fíjate en OperatingSystem.IsIOSVersionAtLeast(26): en dispositivos con iOS 18 o anterior esas APIs no existen, así que el control se queda con su estilo normal. Y como todo está dentro de #if IOS, en Android no cambia nada.

Úsalos en XAML

Liquid Glass<Grid>
    <CollectionView ItemsSource="{Binding Items}" />

    <!-- Botón flotante: capa de navegación, sí lleva Liquid Glass -->
    <controls:GlassButton Text="Nuevo"
                          IsProminent="True"
                          Command="{Binding AddCommand}"
                          HorizontalOptions="End"
                          VerticalOptions="End"
                          Margin="24" />

    <!-- Panel flotante con Liquid Glass -->
    <controls:GlassCard StrokeShape="RoundRectangle 24"
                        StrokeThickness="0"
                        BackgroundColor="Transparent"
                        Padding="16"
                        VerticalOptions="Start"
                        Margin="16">
        <Label Text="3 tareas pendientes" />
    </controls:GlassCard>
</Grid>

Dos detalles importantes:

Si prefieres no escribir esto a mano, hay opciones de terceros: fabricantes como Syncfusion ya tienen contenedores con efecto de vidrio para sus controles, y proyectos de la comunidad como Maui.NativeStyles aplican los estilos de iOS 26 con Mappers parecidos a estos.

Paso 5: prueba como lo haría Apple

Liquid Glass cambia según lo que haya detrás, así que no basta con ver una pantalla. Prueba estos casos en un dispositivo o simulador con iOS 26:

Escenario Qué revisar
Modo claro y oscuro Que los textos de las barras se lean en ambos.
Scroll con contenido colorido debajo Que las barras y botones sigan siendo legibles.
Ajustes > Accesibilidad > Pantalla y tamaño de texto > Reducir transparencia Que la app siga viéndose bien con el Liquid Glass "apagado".
Aumentar contraste Que los bordes y textos no se pierdan.
iPad Que los TitleView y las barras se vean bien (ahí fallan más).
.NET 11 Que tus ToolbarItem secundarios aparezcan en el menú de la barra.

Checklist

✅ Quita UIDesignRequiresCompatibility en una rama y prueba con iOS 26 hoy mismo.

✅ Ejecuta la búsqueda del paso 1 y haz una lista de todo lo que toca las barras.

✅ Quita los colores sólidos de las barras solo en iOS, incluidos los colores de texto.

✅ Reemplaza los TitleView complejos por Title + ToolbarItems, o por un encabezado dentro de la página.

✅ Revisa tus Custom Renderers y handlers que modifican UINavigationBar o UITabBar.

✅ Usa Liquid Glass solo en la capa de navegación, nunca en el contenido.

✅ Prueba con Reducir transparencia y Aumentar contraste.

✅ Planifica el paso a Xcode 27 antes de que el App Store lo exija.

Conclusión

En febrero te recomendé desactivar Liquid Glass para ganar tiempo. Ese tiempo se está acabando: con Xcode 27 el flag desaparece en la práctica, y tu app va a verse con el nuevo diseño quieras o no.

La buena noticia es que en .NET MAUI la mayor parte del trabajo la hace el sistema, porque usamos controles nativos. Lo que te toca es quitar lo que estorba y, si quieres, sumar Liquid Glass donde tiene sentido.

Ya viste:

Mi consejo: haz la prueba hoy. Quita el flag en una rama, abre el simulador y mira qué pasa. Es mucho mejor descubrirlo ahora que el día que Apple te obligue a subir la versión.

¿Tu app ya se ve con Liquid Glass? Cuéntame en X (Twitter) qué fue lo que más se te rompió. Nos leemos pronto 😊


Referencias:

Compartir
Wilson Vargas
Escrito por

Wilson Vargas

Programador .NET con 8 años de experiencia, apasionado por la tecnología. Con habilidades en el desarrollo de aplicaciones utilizando tecnologías de la plataforma .NET.

Posts relacionados

Comentarios