组件

Group

Group 把若干行放进一个圆角框里,行与行之间以细线分隔,就像设置页中的一个分区。每个 JSX 子元素成为一行。可以在框上方加一句简短的标题说明,在下方加一段解释文字。

ui-group.tsx 在线编辑 在新标签页打开
// Group: settings-style rows; each child becomes a row with a divider.
import { mount, signal, Text, View } from "nsh";
import { Group, Stepper } from "nsh/ui/mobile";

function Row(props: { label: string; value: string; onPress?: () => void }) {
  return (
    <View onPress={props.onPress} style={{ flexDirection: "row", justifyContent: "space-between" }}>
      <Text>{props.label}</Text>
      <Text style={{ color: "#737373" }}>{props.value}</Text>
    </View>
  );
}

function App() {
  const notifications = signal(true);
  const size = signal(16);
  return (
    <View style={{ flex: 1, backgroundColor: "#f5f5f5", padding: 16, paddingTop: 24, gap: 24 }}>
      <Group header={<Text>ACCOUNT</Text>}>
        <Row label="Name" value="Ada Lovelace" />
        <Row label="E-mail" value="ada@example.com" />
      </Group>
      <Group
        header={<Text>PREFERENCES</Text>}
        footer={<Text>Tap the first row to toggle it. Rows are the app's JSX; the group adds the box and the dividers.</Text>}
      >
        <Row
          label="Notifications"
          value={notifications() ? "On" : "Off"}
          onPress={() => notifications.set(!notifications())}
        />
        <View style={{ flexDirection: "row", alignItems: "center", justifyContent: "space-between" }}>
          <Text>{`Text size ${size()}`}</Text>
          <Stepper value={size()} min={12} max={24} onChange={(v) => size.set(v)} />
        </View>
      </Group>
    </View>
  );
}

mount(App);
import { Group } from "nsh/ui/mobile";

#用法

import { mount, signal, Text, View } from "nsh";
import { Group } from "nsh/ui/mobile";

function App() {
  const sounds = signal(true);
  return (
    <View style={{ flex: 1, backgroundColor: "#f5f5f5", padding: 16, paddingTop: 48 }}>
      <Group
        header={<Text>NOTIFICATIONS</Text>}
        footer={<Text>Sounds play for new messages only.</Text>}
      >
        <Text>Show previews</Text>
        <View
          onPress={() => sounds.set(!sounds())}
          style={{ flexDirection: "row", justifyContent: "space-between" }}
        >
          <Text>Sounds</Text>
          <Text>{sounds() ? "On" : "Off"}</Text>
        </View>
      </Group>
    </View>
  );
}

mount(App);

#行

Group 把每个子元素包进一行:水平内边距 16 pt,垂直内边距 12 pt,最小高度 44 pt(舒适触控目标的最小尺寸)。内容垂直居中。除第一行外,每一行顶部都有一条 1 pt 的分隔线。

行的内容就是你传入的内容:要在一行里放标签和值,就放一个 flexDirection: "row" 的 <View>;要让这一行可按,就在该视图上加 onPress。子元素增加或删除时(比如通过 <If> 或 <Each>),分组会相应更新行和分隔线。

<Group header={<Text>DEVICES</Text>}>
  <Each of={devices()}>
    {(device) => (
      <View style={{ flexDirection: "row", justifyContent: "space-between" }}>
        <Text>{device().name}</Text>
        <Text style={{ color: "#737373" }}>{device().status}</Text>
      </View>
    )}
  </Each>
</Group>

#标题说明与脚注

标题说明距左侧 16 pt,使用小号(text-sm)的弱化文字;脚注使用更小号(text-xs)的弱化文字。标题说明、圆角框和脚注之间间距 8 pt。两者都是可选的。

#Props

Prop类型默认值说明
headerJSX.Element无框的上方:一句简短的标题说明。
footerJSX.Element无框的下方:解释文字。
childrenJSX.Element无各行,每个子元素一行。
class、classList、style、testID、onLayout、ref作用于分组的根视图(容纳标题说明、圆角框和脚注的那一列)。

Group 没有事件。

#主题

部位主题键
圆角框group_box.background,圆角半径 radius.lg
行文字颜色group_box.foreground
分隔线border
标题说明与脚注文字muted.foreground

参见主题。

#无障碍

Group 不添加任何角色或标签,每一行的内容按你写的样子被朗读。如果某一行可按,请给它的视图设置 accessibilityRole(例如 "button"),必要时再加上 accessibilityLabel。参见无障碍。

#相关内容

  • Card:带页眉和页脚的单个表面。
  • ListView:同样 inset 外观的虚拟化行。
  • Stepper:行内常用的控件。