跳到主要内容

Cell · List 列表行

列表中的信息行,可组合文字、图标、操作和附加内容;使用 List 组织分组或紧凑列表。

代码演示

设置
通知
由行尾开关控制
版本
v1.0
客户
disabled action · handler 会被移除
操作结果:尚未操作

视觉规范

元素规则
整组容器(grouped)c.background 浅灰底(视觉分组),padding: 8space[3]),borderRadius: 12radius.xl),gap: 8
单行c.surface 白底,borderRadius: 10radius.lg),min-height: 56padding: 14space[6],水平 + 垂直同值)
行内布局左 icon (grouped 22 / flush 28 盒) + 中 (title 15/500 + desc 13/subtle) + 右 extra (13/subtle) + arrow (grouped 20 / flush 18)
绝不(grouped)border-bottomhairline 分隔(flush 模式才用 inset hairline)

用法

import { Cell, List, Switch } from '@unif/react-native-design';

<List>
<Cell
title="主题"
extra={{ kind: 'text', value: '跟随系统' }}
arrow
leading="settings"
onPress={openTheme}
/>
<Cell
title="拜访提醒"
desc="按计划自动推送"
extra={{
kind: 'control',
node: (
<Switch
value={notify}
onChange={setNotify}
accessibilityLabel="拜访提醒"
/>
),
}}
/>
<Cell title="版本" extra={{ kind: 'text', value: 12n }} />
</List>;

{
/* 平铺式(无浅灰背景容器,用于嵌套在其它白卡内)*/
}
<List flush>
<Cell
title="客户名"
desc="地址"
extra={{ kind: 'text', value: '¥1,200' }}
arrow
onPress={openCustomer}
/>
</List>;

API

公开内容类型:

type CellTextValue = string | number | bigint;
type CellLeading = IconName | { kind: 'display'; node: ReactElement };
type CellExtra =
| { kind: 'text'; value: CellTextValue }
| {
kind: 'display';
node: ReactElement;
accessibilityText?: string;
}
| { kind: 'control'; node: ReactElement };

type ActionableCellExtra = Exclude<CellExtra, { kind: 'control' }>;
type StaticCellExtra =
| Extract<CellExtra, { kind: 'text' }>
| {
kind: 'display';
node: ReactElement;
accessibilityText?: never;
};

公开 CellExtra 保持完整三分联合;CellProps 再按分支收紧。accessibilityText 只属于 actionable display,static display 精确禁止该字段。

<Cell>

参数类型默认值说明
titleCellTextValue主标题(必填);始终由库内 <Text> + stringifyCellText 安全渲染
titleLinesnumber1主标题的 numberOfLines
descCellTextValue副标题 / 描述;始终由库内 <Text> 安全渲染,最多 2 行
extraCellExtra三种公开配置;actionable 可用 text/display,static 仅 text/装饰 display,control 仅 control
arrowbooleanfalse仅 actionable 可用;显示 chevron-right,danger 时仍不渲染
leadingCellLeading图标名,或 { kind: 'display', node } 纯展示节点
onPress() => voidactionable 分支必填;control/static 禁止
disabledbooleanfalse仅 actionable 可用;禁用时移除 handler、半透明并上报 disabled
dangerbooleanfalse危险态:icon 盒子 + 标题用 error 红,且不渲染 arrow(常用于退出登录 / 删除等)
styleStyleProp<ViewStyle>额外样式覆盖(合并到 cell 容器的 style 数组)
testIDstringE2E / 测试定位
accessibilityLabelstring自动组合仅 actionable 可用;覆盖自动名称
accessibilityHintstring仅 actionable 可用;说明操作结果

CellProps 是三个互斥分支:

分支必要条件可用 extra外层语义
actionableonPress 必填text / displayRNGH Pressable + button
controlextra.kind === 'control'control本地 View;control 自己承担交互与名称
staticonPresstext / 无 accessibilityTextdisplay本地 View;禁止 arrow / disabled / action a11y props

<List>

参数类型默认值说明
childrenReactNode一组 <Cell>
flushbooleanfalse透明背景(嵌套用);省略则白卡 + 8px gap + 浅灰底容器
divider'full' | 'none''full'flush 模式下行间分隔线:'full' 铺满全宽 hairline / 'none' 不画
styleStyleProp<ViewStyle>额外样式覆盖
testIDstringE2E / 测试定位

无障碍(a11y)

来源:src/components/ui/Cell/Cell.tsxcontent.tstypes.ts

  • actionable 是唯一外层可访问操作:RNGH Pressable 固定为 button。默认名称依次组合 trim 后非空的 titledesc 与 extra 文本,使用中文顿隔 ;actionable display 的 accessibilityText 只有非空白时才贡献。trim 后非空的显式 accessibilityLabel 优先,空白覆盖回退自动名称;最终名称仍为空时整行失败关闭为本地 View,不保留外层 handler/button/arrow,并在 effect 诊断。
  • disabled=true 时 actionable 同时设置 disabled state 和 onPress={undefined},不会留下可调用 handler。
  • control/static 都渲染本地 View,不创建外层 action 或用于合并名称的 a11y node。control 的 node 必须自己提供 role、state、handler 与 accessible name。
  • 所有 leading、自定义 display extra 与 chevron 都由库内本地 View 包裹,并用共享隐藏属性移出 a11y tree;只有 actionable display 的 accessibilityText 会进入外层名称,不形成第二焦点。
  • titledesctext extra 始终由库内 Text 渲染,0 / bigint 不会成为 View 的裸 child。static 需要语义内容时必须使用 kind: 'text',由可见 Text 自然朗读;static display 始终是装饰内容,类型精确禁止 accessibilityText
// 默认读作“设备,在线”;display node 本身不形成第二焦点
<Cell
title="设备"
extra={{
kind: 'display',
node: <StatusDot status="active" />,
accessibilityText: '在线',
}}
onPress={openDevice}
/>

// control Cell 外层不是 button;Switch 自己命名
<Cell
title="通知"
extra={{
kind: 'control',
node: (
<Switch
value={notify}
onChange={setNotify}
accessibilityLabel="通知"
/>
),
}}
/>

// static 语义内容使用 text;外层保持普通 View
<Cell title="状态" extra={{ kind: 'text', value: '在线' }} />

// static display 仅作装饰,不能声明 accessibilityText
<Cell
title="品牌"
extra={{ kind: 'display', node: <BrandBadge /> }}
/>

与 Form 的区别

用途选哪个
数据展示 / 跳转Cell · List — 白卡 + gap
数据录入 / 表单Form — 白卡 + 行间 hairline

主题键(Tokens)

读取来源:src/components/ui/Cell/styles.ts

Token来源作用
c.surfaceuseColors()grouped 模式下单行白卡背景色
c.foregrounduseColors()主标题文字色(title / titleFlush
c.foregroundSubtleuseColors()副标题 / extra 文字色(grouped 模式)
c.foregroundMuteduseColors()副标题 / extra 文字色(flush 模式,另加 opacity: 0.55
c.backgrounduseColors()<List> grouped 模式外容器背景色(浅灰底)
c.outlineuseColors()flush 模式行间 hairline 分隔线颜色
radius.lg静态 tokengrouped 模式单行卡片圆角
radius.xl静态 token<List> grouped 模式外容器圆角
space[5] / space[6] / space[3]静态 token行内 leading↔body↔extra gap(12)/ 行内水平+垂直内边距(14)/ List 行间 gap + 容器 padding(8)
space[4]静态 tokenflush 模式行内元素间 gap(cellFlush.gap
type.body / type.xs静态 token主标题 / 副标题字号(grouped 模式)
fw.medium静态 token主标题字重
StyleSheet.hairlineWidthReact Nativeflush 模式分隔线物理宽度(不参与 token 缩放)