Diese Seite wurde maschinell übersetzt und kann Fehler enthalten. Das englische Original lesen

Elemente

Tastatur

env(keyboard-inset-height) ist die Höhe der Software-Tastatur über der Oberfläche, solange die Tastatur ausgeblendet ist, ist der Wert 0. Als unteres Padding oder Margin einer View hält sie den Inhalt oberhalb der Tastatur: Wenn die Tastatur ein- oder ausgeblendet wird, schafft die View Platz in Höhe der Tastatur, und die Änderung wird nativ mit der Tastatur animiert. Verwende sie für Inhalte außerhalb von Scroll-Views, etwa eine Nachrichtenleiste am unteren Rand eines Chat-Bildschirms; Eingabefelder innerhalb einer Scroll-View oder einer List werden nativ in den sichtbaren Bereich gescrollt. Dazu gehören Keyboard.dismiss(), das die Tastatur ausblendet, und die Höhe der Tastatur für eigene Layouts.

el-keyboard.tsx
el-keyboard.tsxLive
import { mount, Scroll, signal, Text, View } from "nsh";
import { Input } from "nsh/base";
import { Button, Switch } from "nsh/base";
import { Keyboard, keyboardFrame } from "nsh";
import { button, buttonText, desktop, field, tint, ui } from "./palette";

function App() {
  const draft = signal("");
  const messages = signal(["Type below: the bar stays above the keyboard."]);
  const behavior = signal<"padding" | "height">("padding");
  const enabled = signal(true);
  const send = () => {
    if (!draft().trim()) return;
    messages.update((list) => [...list, draft().trim()]);
    draft.set("");
  };
  const chip = (on: () => boolean) => button("secondary", { on, size: "sm" });
  const chipText = (on: () => boolean) => buttonText("secondary", { on });
  const isPadding = () => behavior() === "padding";
  const isHeight = () => behavior() === "height";
  return (
    <View
      style={{
        flex: 1,
        backgroundColor: behavior() === "height" ? tint(ui().info, 0.12) : ui().page,
        // Bottom padding (or margin) by the keyboard's height, while enabled.
        ...(!enabled() ? {} : behavior() === "padding" ? { paddingBottom: "env(keyboard-inset-height)" } : { marginBottom: "env(keyboard-inset-height)" }),
      }}
    >
      <View style={{ padding: 20, paddingTop: 24, paddingBottom: 8, gap: 8 }}>
        <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>keyboard inset</Text>
        <Text style={{ color: ui().muted }}>
          {desktop
            ? "Desktops type with a hardware keyboard: its height stays 0 and the view keeps its layout. Open this on a phone to see it move."
            : "Tap the message field: the bar moves up with the keyboard."}
        </Text>
        <View style={{ flexDirection: "row", flexWrap: "wrap", gap: 6 }}>
          <Button onPress={() => behavior.set("padding")} selected={isPadding()} {...chip(isPadding)}>
            <Text style={chipText(isPadding)}>padding</Text>
          </Button>
          <Button onPress={() => behavior.set("height")} selected={isHeight()} {...chip(isHeight)}>
            <Text style={chipText(isHeight)}>height</Text>
          </Button>
          <Switch
            checked={enabled()}
            onChange={({ checked }) => enabled.set(checked)}
            class="flex-row items-center gap-2 px-1 active:opacity-70"
            trackClass="w-9 rounded-full p-0.5 transition-colors motion-reduce:transition-none"
            trackStyle={enabled() ? ui().accentFill : ui().inset}
            thumbClass="size-4 rounded-full transition-transform motion-reduce:transition-none checked:translate-x-4"
            thumbStyle={enabled() ? { backgroundColor: ui().onAccent } : ui().raised}
          >
            <Text style={{ color: ui().text, fontSize: 13, fontWeight: "600" }}>enabled {String(enabled())}</Text>
          </Switch>
        </View>
        <Text style={{ color: ui().accent, fontSize: 13 }}>
          keyboardFrame(): height {Math.round(keyboardFrame().height)} · duration {Math.round(keyboardFrame().duration)} ms
        </Text>
      </View>

      <Scroll style={{ flex: 1 }} keyboardDismissMode="interactive">
        <View style={{ padding: 20, paddingTop: 4, gap: 8 }}>
          <Each of={messages()}>
            {(text) => (
              <View style={{ ...ui().row, alignSelf: "flex-start", maxWidth: 320, borderRadius: 14, paddingHorizontal: 12, paddingVertical: 8 }}>
                <Text style={{ color: ui().text }}>{text()}</Text>
              </View>
            )}
          </Each>
        </View>
      </Scroll>

      <View style={{ flexDirection: "row", gap: 8, padding: 12, paddingHorizontal: desktop ? 20 : 12, borderTopWidth: 1, borderTopColor: ui().border, backgroundColor: ui().page }}>
        <Input
          value={draft()}
          onChange={({ value }) => draft.set(value)}
          onSubmit={send}
          testID="message"
          returnKeyType="send"
          placeholder="Message"
          {...field({ style: { flex: 1 } })}
        />
        <Button onPress={send} {...button("primary")}>
          <Text style={buttonText("primary")}>Send</Text>
        </Button>
        <Button onPress={() => Keyboard.dismiss()} {...button()}>
          <Text style={buttonText()}>Done</Text>
        </Button>
      </View>
    </View>
  );
}

mount(App);
use nsh_core::prelude::*;

fn chat() -> impl IntoElement {
    let draft = signal(String::new());
    view()
        .flex_1()
        .bg(white())
        .pb_keyboard()
        .child(scroll().flex_1().child(text("Messages…").p_4()))
        .child(
            view()
                .flex_row()
                .gap_2()
                .p_2()
                .border_t_1()
                .border_color(rgb(0xe5e5e5))
                .child(
                    input()
                        .value(draft)
                        .on_change(move |v: &str| draft.set(v.to_owned()))
                        .placeholder("Message")
                        .flex_1()
                        .p_2(),
                ),
        )
}

Die volle Tastaturhöhe eignet sich für eine View, die bis zum unteren Bildschirmrand reicht, etwa den Inhalt eines Bildschirms. Befindet sich darunter etwas, zum Beispiel eine Tab-Leiste, ziehst du diese mit einer Länge ab: calc(env(keyboard-inset-height) + -49px) hält eine View oberhalb einer 49 pt hohen Tab-Leiste, und calc(env(keyboard-inset-height) + 12px) fügt Abstand über der Tastatur hinzu. Ein Padding ist mindestens 0.

#Padding oder Margin

Stil So entsteht Platz
paddingBottom: "env(keyboard-inset-height)" (Tailwind pb-[env(keyboard-inset-height)], Rust .pb_keyboard()) Der Inhalt darüber schrumpft; der Hintergrund reicht weiterhin bis zum unteren Bildschirmrand.
marginBottom: "env(keyboard-inset-height)" (Tailwind mb-[env(keyboard-inset-height)], Rust .mb_keyboard()) Die gesamte View samt Hintergrund endet am oberen Rand der Tastatur.

Die Tastaturhöhe wird nur der Länge in derselben Deklaration hinzugefügt, daher kombiniert eine View sie mit eigenem Abstand in calc(). In Rust fügen .pb_keyboard_plus(px(..)) und .mb_keyboard_plus(px(..)) eine Länge hinzu.

use nsh_core::prelude::*;

fn sign_in() -> impl IntoElement {
    view()
        .mb_keyboard_plus(px(-49.0))
        .flex_1()
        .p_4()
        .gap_3()
        .child(input().placeholder("E-mail").keyboard_type(KeyboardType::Email))
}

Hier deckt eine 49 pt hohe Tab-Leiste unterhalb der View bereits einen Teil der Tastaturhöhe ab. Um den Platz abzuschalten, lässt du die Variable im Stil weg, zum Beispiel über eine Bedingung auf einem Signal.

#Die Tastatur ausblenden

Keyboard.dismiss() aus nsh entfernt den Fokus vom fokussierten Eingabefeld und blendet damit die Tastatur aus. Ist kein Eingabefeld fokussiert, bleibt alles unverändert. Rust-Komponenten rufen dismiss_keyboard() auf.

use nsh_base::button;
use nsh_core::prelude::*;

fn done() -> impl IntoElement {
    button()
        .on_press(|| dismiss_keyboard())
        .rounded_lg()
        .bg(rgb(0x2563eb))
        .px_4()
        .py_3()
        .child(text("Done").text_color(white()))
}

#Die Höhe der Tastatur

TSX Rust Rückgabe
keyboardFrame() keyboard_height(), keyboard_duration() Die Höhe der Software-Tastatur über der NSH-Oberfläche in Punkten (0, solange sie ausgeblendet ist) sowie die Dauer ihrer Ein- bzw. Ausblendanimation in Millisekunden.

Beide sind reaktiv: Ein Effect, ein JSX-Ausdruck oder eine Style-Closure, die sie liest, wird erneut ausgeführt, wenn die Tastatur ein- oder ausgeblendet wird oder ihre Höhe ändert.

use nsh_core::prelude::*;

fn message_bar() -> impl IntoElement {
    view()
        .flex_row()
        .p_2()
        .pb(move || {
            // The home indicator's inset only matters while the keyboard is hidden.
            let home = if keyboard_height() > Points::ZERO {
                Points::ZERO
            } else {
                safe_area().bottom
            };
            px(8.0) + home
        })
        .child(input().placeholder("Message").flex_1())
}

Die Höhe ist der Teil der Tastatur, der die NSH-Oberfläche überlagert. Wenn das Fenster selbst für die Tastatur schrumpft (eine Android-Activity, die ihre Größe anpasst) oder wenn NSH in eine View eingebettet ist, die oberhalb der Tastatur endet, ist die Höhe 0.

#Hinweise zu Plattformen

  • iOS: Der Platz wird mit der eigenen Dauer der Tastatur und einer Ease-in-ease-out-Kurve animiert.
  • Android: Wenn das Fenster für die Tastatur schrumpft (eine Activity, die ihre Größe anpasst), endet der Inhalt bereits oberhalb der Tastatur, und die Variable ist 0. Wenn die Tastatur die View überlagert, schafft sie Platz wie unter iOS.
  • Desktops und Mac Catalyst verwenden eine Hardware-Tastatur: Die Variable ist 0, und die View behält ihr Layout.
  • Web: Die Variable ist die des Browsers (die der VirtualKeyboard API).

Siehe Formulare und Tastatur für Fokusreihenfolge, Return-Tasten und Eingabezubehör sowie Safe Area für die übrigen Umgebungsvariablen.