Questa pagina è stata tradotta automaticamente e può contenere errori. Leggi l'originale in inglese

Documentazione

Codice specifico per piattaforma

Un solo bundle NSH funziona su iOS, Android, macOS, Windows e Linux (e in Mac Catalyst), e nei browser tramite il web runtime. La maggior parte di un’app non richiede alcun controllo della piattaforma: elementi, stili, layout e moduli si comportano allo stesso modo ovunque, e i componenti che costruisci con essi hanno lo stesso aspetto ovunque. Quando qualcosa è davvero specifico di una piattaforma, NSH gli riserva un posto ben definito, così il codice di piattaforma resta visibile e circoscritto:

RustTSXPer
Metodi builder (.ripple(..), .input_accessory(..))ios={{…}}, android={{…}}, desktop={{…}}, web={{…}}Prop che esistono solo su una piattaforma.
on_back_press, nsh_core::element::desktopnsh/mobile, nsh/desktopAPI presenti solo sulle piattaforme mobile o solo sui desktop.
os(), idiom(), is_desktop()platform.os, platform.desktop, platform.selectScegliere valori o codice per piattaforma.
.when(os() == Os::Ios, ..)Classi ios: / android: / web:Stili per piattaforma.

#Desktop e mobile

Ogni piattaforma è desktop o mobile, secondo un’unica regola. Desktop sono macOS, Windows, Linux e i browser nell’idioma desktop (un mouse e una finestra ampia, il web). Mobile sono iOS, Android e i browser nell’idioma telefono o tablet; Mac Catalyst esegue il backend iOS, quindi è anch’esso mobile, con prop ios={{…}}. Seguono questa regola le prop desktop={{…}}, platform.select({ desktop, mobile }), platform.desktop e platform.idiom === "desktop", così come i componenti di nsh/base (un menu è un popup sui desktop e un foglio su mobile) e, in Rust, is_desktop().

Il isAvailable di nsh/desktop risponde a una domanda più ristretta: se le API di finestra e menu di quel modulo funzionano, il che avviene su macOS, Windows e Linux. Usa platform.desktop per condizionare layout, densità e input, e isAvailable per le chiamate a Window e Menu.

#Prop specifiche della piattaforma

In Rust, una prop che esiste su una sola piattaforma è un metodo builder come gli altri (.ripple(..), .elevation(..) per Android, .input_accessory(..) per iOS, .window_drag(..) per i desktop); le altre piattaforme la ignorano. In TSX, le prop che esistono su una sola piattaforma sono raggruppate in un oggetto che porta il suo nome. Ogni elemento accetta ios, android, desktop (macOS, Windows, Linux e i browser nell’idioma desktop) e web (browser); sulle altre piattaforme l’oggetto viene ignorato e, sulla piattaforma di appartenenza, vengono applicate solo le sue chiavi. Un browser desktop applica sia desktop sia web.

use nsh_base::dialog;
use nsh_core::{
    Ripple,
    element::{AutoFill, Orientation}, prelude::*,
};

view()
    .on_press(open)
    .active(|s| s.opacity(0.6))
    .ripple(Ripple {
        color: Some(rgba(0x0000001f).into()),
        ..Ripple::default()
    })
    .elevation(px(4.0))
    .p_4()
    .rounded(px(12.0))
    .bg(white())
    .child(text("Open"))

input().placeholder("Code").auto_fill(AutoFill::OneTimeCode)

when(shown, || {
    dialog()
        .supported_orientations([Orientation::Portrait])
        .status_bar_translucent(true)
        .child(…)
})

Gli oggetti TSX sono reattivi come qualsiasi prop; una chiave rimossa dall’oggetto viene azzerata.

Ciò che esiste oggi:

RustTSXSuDescrizione
.ripple(Ripple { .. })android={{ ripple }}ogni elementoL’effetto ripple material durante la pressione: color, borderless, radius, foreground.
.elevation(..)android={{ elevation }}ogni elementoL’ombra material, in punti, a partire dalla forma della vista.
android={{ accessibilityLiveRegion }}ogni elemento"none", "polite" o "assertive": TalkBack annuncia i cambiamenti della vista.
.status_bar_translucent(..)android={{ statusBarTranslucent }}DialogIl contenuto del dialogo si estende sotto la barra di stato.
.input_accessory(..)ios={{ inputAccessoryViewID }}InputIl InputAccessoryView mostrato sopra la tastiera.
.auto_fill(..)ios={{ textContentType }}InputI nomi di iOS per i tipi di compilazione automatica (AutoFill di Rust copre entrambe le piattaforme).
.supported_orientations(..)ios={{ supportedOrientations }}DialogGli orientamenti che consente.
.back_forward_gestures(..)ios={{ allowsBackForwardNavigationGestures }}WebViewScorrimento indietro e avanti nella cronologia delle pagine.
.header_right_system_item(..)ios={{ headerRightSystemItem }}NavPageIl pulsante di barra nativo di UIKit alla fine dell’intestazione, che esegue headerRight alla pressione.
.header_left_system_item(..)ios={{ headerLeftSystemItem }}NavPageIl pulsante di barra nativo di UIKit all’inizio dell’intestazione, che esegue headerLeft alla pressione.
.header_right_symbol(..)ios={{ headerRightSymbol }}NavPageIl pulsante di barra nativo di UIKit che mostra un SF Symbol alla fine dell’intestazione, che esegue headerRight alla pressione.
.header_left_symbol(..)ios={{ headerLeftSymbol }}NavPageIl pulsante di barra nativo di UIKit che mostra un SF Symbol all’inizio dell’intestazione, che esegue headerLeft alla pressione.
.back_forward_gestures(..)desktop={{ allowsBackForwardNavigationGestures }}WebViewmacOS: gli swipe a due dita sul trackpad vanno indietro e avanti nella cronologia delle pagine; Windows: swipe sul touchscreen; Linux: swipe sul touchpad.
.window_drag(..)desktop={{ windowDrag }}ogni elementoPremendolo si trascina la finestra, come farebbe la barra del titolo di sistema (vedi nsh/desktop).

In TSX, desktop={{…}} e web={{…}} sono accettati ovunque. I tipi (IOSProps, AndroidProps, DesktopProps e le loro forme per elemento) indicano al tuo editor cosa accetta ciascun elemento.

Ciò che un elemento significa su ogni piattaforma è una prop di primo livello (in Rust un metodo con lo stesso nome), applicata dove ha un significato: title, headerStyle, headerLargeTitle e headerBackTitle di NavPage configurano l’intestazione di sistema di iOS e Android, il suo slot header è l’intestazione dei desktop e del web, e presentation di Dialog sceglie i fogli di iOS. closeOnBackdropPress, pagingEnabled, refreshing, hitSlop e le altre di AlertDialog.show funzionano su ogni piattaforma. Una funzionalità di sistema propria di una piattaforma va nel suo oggetto e, quando più piattaforme la hanno, in ciascuno dei rispettivi oggetti con lo stesso nome: allowsBackForwardNavigationGestures di WebView, gli swipe di sistema nella cronologia delle pagine, si trova in ios={{…}} e desktop={{…}}.

#Moduli di piattaforma

In Rust, le API che esistono su una sola piattaforma sono funzioni di nsh_core::prelude (on_back_press, input_accessory_view) e di nsh_core::element::desktop (la finestra: set_title, set_title_bar, title_bar, minimize, toggle_maximize, toggle_full_screen, set_frame, set_level, order_front, close_window; i menu: set_application_menu, popup_menu); altrove non fanno nulla. In TSX, nsh/mobile contiene le API di iOS e Android (alcune di una sola piattaforma), nsh/desktop quelle dei desktop. Entrambi si possono importare su ogni piattaforma, così un solo bundle funziona ovunque: sulle altre piattaforme le loro funzioni ritornano subito e i loro componenti non occupano spazio. Ognuno esporta isAvailable, che è true sulle proprie piattaforme; platform.os permette di distinguerli.

#nsh/mobile

isAvailable è true su iOS (con Mac Catalyst) e Android. Entrambe le piattaforme hanno TabBar, la barra delle schede di sistema.

#BackHandler (Android)

RustTSXDescrizione
on_back_press(listener)BackHandler.on("press", listener)Ascolta il pulsante indietro dopo i dialoghi e prima degli stack; restituisci true quando è gestito. Il listener segue il componente (o l’effetto) che lo ha aggiunto; in TSX la chiamata restituisce anche una funzione che lo ferma prima.
BackHandler.exitApp()Esce dall’app.
use nsh_core::prelude::*;

fn player() -> impl IntoElement {
    let full_screen = signal(false);
    // Back leaves full screen before it leaves the page. The listener goes
    // with the view.
    on_back_press(move || {
        if !full_screen.get_untracked() {
            return false;
        }
        full_screen.set(false);
        true
    });
    // …
}

Il pulsante indietro viene gestito prima dal dialogo in primo piano, poi dai listener di ritorno (il più recente per primo), poi dallo stack di navigazione in primo piano, e l’app termina se nessuno lo ha gestito. Vedi Navigation.

#InputAccessoryView (iOS)

RustTSXDescrizione
input_accessory_view(native_id)InputAccessoryViewUna barra sopra la tastiera degli input che indicano il suo native id (.input_accessory(..), ios={{ inputAccessoryViewID }}).

Vedi Forms and the keyboard.

#nsh/desktop

Le app Rust disegnano le proprie barre del titolo con nsh_core::element::desktop (Building with Rust). Il modulo TSX:

ExportDescrizione
WindowLa finestra: setTitle, setTitleBar({ style: "hidden" }) per una barra del titolo propria dell’app, minimize, toggleMaximize, toggleFullScreen, close.
titleBarL’altezza della barra del titolo nascosta e lo spazio occupato dai controlli di finestra del sistema (reattivo).
MenusetApplicationMenu(items) (la barra dei menu, con scorciatoie) e popup(items, at?) (menu contestuali).
isAvailabletrue dove le API di finestra e menu funzionano: macOS, Windows e Linux. I browser desktop hanno platform.desktop e mantengono la finestra e i menu del browser.

Vedi nsh/desktop.

#La barra di stato

Su entrambe le piattaforme la barra di stato appartiene alla pagina o al dialogo in primo piano, come in UIKit, dove decide il view controller più in alto: NavPage e Dialog accettano statusBar (in Rust .status_bar(StatusBarStyle::Light), oppure un StatusBarSetting per gli altri campi) con foreground ("auto", "light" per sfondi scuri, "dark" per sfondi chiari), hidden e animated. Vince la pagina o il dialogo mostrato più di recente, campo per campo, e quando scompare si applica di nuovo quello sottostante. "statusBar" di nsh.json è il valore predefinito dell’app sotto di essi.

use nsh_base::nav_page;
use nsh_core::prelude::*;

fn photo_viewer() -> impl IntoElement {
    nav_page()
        .header_visible(false)
        .status_bar(StatusBarStyle::Light)
        .child(view().flex_1().bg(black()))
}

In un’app incorporata in un’app nativa, su iOS è il view controller dell’app host a decidere la barra di stato. Un’app che dichiara "capabilities" in nsh.json ha bisogno di "statusBar": true per modificarla.

#platform.os e platform.select

os() in Rust e la costante platform da nsh in TSX indicano dove viene eseguita l’app: Os::Ios, Os::Android, Os::MacOs, Os::Windows, Os::Linux o Os::Web, e platform.os "ios", "android", "macos", "windows", "linux" o "web" (Mac Catalyst è "ios", con platform.catalyst in entrambi i suoi idiomi; il backend macOS è "macos", il backend Linux "linux" e il backend Windows "windows", e i loro elementi applicano le prop desktop; i browser sono "web" e applicano anche le prop desktop quando platform.desktop è true). Vedi Device and environment per la versione, l’idioma e il resto.

use nsh_core::{element::Os, prelude::*};

if os() == Os::Android {
    // …
}

#platform.select

In Rust un match os() sceglie il valore, con is_desktop() per i desktop. In TSX, platform.select(spec) restituisce il valore per questa piattaforma. Cerca la chiave propria del sistema operativo, poi desktop o mobile secondo la regola sopra (platform.desktop), poi native (ogni piattaforma tranne il web), poi default:

use nsh_core::{element::Os, prelude::*};

fn card() -> View {
    let card = view().rounded(px(12.0)).bg(white());
    match os() {
        Os::Ios => card.shadow_md(),
        Os::Android => card.border_1().border_color(rgb(0xe5e7eb)),
        _ => card,
    }
}

let hint = match os() {
    Os::Ios => "Swipe down to close",
    Os::Android => "Press back to close",
    _ => "Close",
};

Restituisce undefined quando nulla corrisponde e non c’è default.

#Rendere componenti diversi

Scegli i componenti nello stesso modo, a livello di modulo (TSX) quando la scelta non cambia mai:

fn spinner() -> AnyElement {
    if os() == Os::Ios {
        ios_spinner().into_element()
    } else {
        material_spinner().into_element()
    }
}

oppure inline con when / <If>:

when(os() == Os::Ios, || input_accessory_view("bar").child(…))
    .otherwise(|| text("Android has no input accessories."))

#Varianti di piattaforma in Tailwind

Rust applica gli stili per piattaforma con .when(os() == Os::Ios, |v| ..); in TSX, le varianti ios:, android: e web: applicano classi su una sola piattaforma:

view()
    .rounded_xl()
    .bg(white())
    .p_4()
    .when(os() == Os::Ios, |v| v.shadow_md())
    .when(os() == Os::Android, |v| v.border_1().border_color(rgb(0xe4e4e7)))

#Preferisci il comportamento condiviso

Prima di ricorrere a un controllo della piattaforma, valuta se la differenza conta davvero per i tuoi utenti. Elementi e stili si adattano già al comportamento nativo di ciascuna piattaforma dove deve differire (fisica dello scorrimento, rendering del testo, tastiere, accessibilità), restando uguali dove gli utenti si aspettano coerenza (l’aspetto proprio della tua app). I controlli della piattaforma è meglio riservarli alle convenzioni di piattaforma su cui gli utenti fanno affidamento: il pulsante indietro e i toast di Android, i fogli e i titoli grandi di iOS, i nomi di compilazione automatica, il ripple di Android.

#Vedi anche