Ir al contenido
Los plugins ya cargan en macOS y en el Apple Watch

Vistas nativas de verdad.
Sin WebView por ninguna parte.

Escribe Angular. Obtienes un UIView, un android.view.View, un NSView o una vista de SwiftUI — el control de verdad, del sistema de verdad, en ocho plataformas.
npx @angular/cli@latest new mi-appcd mi-app && an init

25 primitivas · 8 plataformas · un núcleo en Rust

Todo el argumento

Una plantilla. Lo que esa plataforma traiga de verdad.

Aquí no se dibuja nada para que se parezca a un control. La plantilla no cambia de una plataforma a otra: lo que cambia es la clase que monta el framework, y donde una plataforma no tiene equivalente no se monta nada y el host dice por qué.

<an-view [style.gap]="'16'">
<an-text [fontSize]="28">Avisos</an-text>
<an-switch
[on]="avisos()"
(onChange)="avisos.set($event)" />
</an-view>

an-switch se convierte en

UISwitch

El interruptor del propio sistema: su animación, su háptico, su rasgo de accesibilidad, y el aspecto que tenga en la siguiente versión de iOS.

MaterialSwitch

Material 3, resuelto sin Gradle. Sigue el tema del dispositivo, incluido el color dinámico que el usuario haya sacado de su fondo de pantalla.

NSSwitch

AppKit, en una ventana que se redimensiona — con un puntero que tiene forma y un estado de hover, dos cosas que un dedo no tiene.

Toggle

El único host que no es una jerarquía de vistas: el árbol se replica en un modelo que SwiftUI repinta.

UISwitch

El mismo host que el móvil, en una escena con ventana. Una ventana en el espacio no es una pantalla, pero sigue siendo UIKit.

MaterialSwitch

El host del móvil en una pantalla redonda, donde el área segura es por donde llega el margen del bisel.

no se monta nada

UISwitch no está en el SDK de tvOS: una tele se maneja con un mando. El layout deja el hueco que había medido y el host lo dice una vez, en el log.

Controles de verdad, no imitaciones

Aquí no se dibuja nada para que se parezca a un control. El interruptor de tu plantilla es el del sistema, así que se ve y se comporta como ese control se comporte en esa versión del sistema, y envejece con la plataforma en vez de con este repositorio.

  • iOS · iPadOSUISwitch
  • AndroidMaterialSwitch
  • macOSNSSwitch
  • watchOSToggle
  • visionOSUISwitch
  • tvOSno está en el SDK

El layout no es de la plataforma

UIKit, AppKit y Android colocan de formas distintas, y SwiftUI directamente no te deja colocar — así que el layout se va de la plataforma entera. Flexbox corre una vez, en un núcleo de Rust sobre taffy, y a cada host se le entregan frames absolutos en puntos lógicos. La misma plantilla se coloca igual en un móvil, en una tele y en un reloj.

Angular tal cual es

Señales, @if, @for, el router con parámetros, plantillas AOT, inyección de dependencias. Sin zonas, y no de forma opcional: sin zone.js no hay timers ni XHR que parchear dentro del motor, que es la mayor parte de lo que hace doloroso esto en otros sitios. Sin dialecto, sin subconjunto.

Un hueco nunca es silencioso

Una prop que ningún host lee, un estilo que nadie reconoce, un evento que una plataforma no puede entregar, un plugin al que le falta una plataforma: cada uno avisa, o detiene la compilación. Una primitiva que no está soportada en algún sitio tiene que decirlo por escrito, y hay scripts que lo exigen.

[angular-native] (pinch) does not arrive on watchOS:
  MagnifyGesture is @available(watchOS, unavailable),
  and two fingers do not fit on a 40 mm screen

Grabado en un simulador, no maquetado

Dos apps de examples/, funcionando.

Las dos son componentes de Angular normales —señales, @for, @if— y todos los controles que llevan son los de la plataforma. Las grabaciones son el simulador de iOS, manejado a mano: el campo de búsqueda es un UISearchBar, el selector de talla un UISegmentedControl, la cantidad un UIStepper y las estrellas son SF Symbols.

Una galería que recoloca

Dos columnas repartidas por altura acumulada, un campo de búsqueda del sistema, una tira de categorías y tirar para recargar. En el motor de layout no hay grid y no hace falta: una cascada son dos columnas flex, resueltas una vez en Rust.

  • an-search-bar
  • an-segmented-control
  • an-image
  • an-scroll-view
Cómo funcionan las listas largas

Una ficha de producto que se arrastra

El carrusel es lo único aquí que no es un control del sistema, porque ninguna plataforma trae uno — así que es un gesto de arrastre moviendo una transformación, y al soltar el resto lo termina la plataforma en su propio hilo de dibujo. El stepper y el interruptor de al lado son de UIKit.

  • an-stepper
  • an-switch
  • an-segmented-control
  • (pan)
  • [animate]
Gestos y animación

Dónde corre

Ocho plataformas, un bundle

El mismo bundle en todas. Lo que cambia no es el código: es qué controles trae esa plataforma, y cada hueco está contado con su motivo.

  • iOS · iPadOS

    Pinta conUIKit

    Las 25 primitivas

  • Android

    Pinta conandroid.view + Material 3

    Las 25 primitivas

  • macOS

    Pinta conAppKit

    Las 25 primitivas

  • tvOS

    Pinta conUIKit + motor de foco

    20 de 25 — una tele no tiene interruptor ni deslizador

  • visionOS

    Pinta conUIKit en una escena con ventana

    Las 25 primitivas

  • watchOS

    Pinta conSwiftUI

    17 de 25

  • Wear OS

    Pinta conandroid.view

    18 de 25

  • HarmonyOS · Windows

    Pinta con

    Sin empezar

En un minuto

Cuatro comandos sobre un proyecto que ya tenías

Un proyecto de la CLI de Angular, sin modificar, corriendo sobre vistas nativas. No se mueve nada a este repositorio y ng build sigue funcionando igual.

an init
Dependencias, tsconfig y punto de entrada. No toca src/main.ts ni angular.json.
an add ios
Escribe ios/Info.plist, y a partir de ahí es tuyo.
an ios
Compila, monta el .app sin Xcode y lo lanza en el simulador.
Ventana de terminal
npx @angular/cli@latest new mi-app && cd mi-app
an init
an add ios
an ios

Escribe Angular. Publica nativo.

Un proyecto de ng new corriente, cuatro comandos, y está corriendo sobre vistas de UIKit y de Material de verdad.

Empezar