Cell
列表项与分组容器,承载设置项、信息展示等纵向列表
单元格(Cell)是移动端最常见的列表行:左侧图标、标题与副标题、右侧文案与箭头。传了 onPress / onLongPress 时根节点渲染为 Pressable,否则退化成纯展示的 View —— 不会给静态列表凭空加上一个可聚焦节点。CellGroup 负责把若干行收成一张卡片,并在行与行之间插入分隔线。
import { Cell, CellGroup } from '@skyroc/native-ui';基础用法
title、subtitle、trailing 三者可以任意组合,传 string 时会自动包一层 Text 承接主题字号与颜色;传自定义节点则原样渲染。
import { Cell } from '@skyroc/native-ui';
import { View } from 'react-native';
const CellBasic = () => {
return (
<View className="bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell title="单行标题" />
<Cell
subtitle="用于补充说明当前内容"
title="带描述信息"
/>
<Cell
subtitle="标题、描述与右侧内容可以同时使用"
title="完整信息"
trailing="详情"
/>
</View>
</View>
);
};
export { CellBasic };何时使用
- 设置页、个人中心、订单详情这类「标签 + 值」的纵向列表。
- 需要整行可点击的入口时,直接给
Cell传onPress,不要在外面再套一层Pressable。 - 只做信息展示、不需要点击时不传回调即可,组件会自动渲染为
View。 - 需要卡片式分组、分组标题和分隔线时用
CellGroup包一层。
点击与箭头
onPress 或 onLongPress 任一存在时,整行变成可点击的 Pressable,并默认显示右箭头。箭头的显示规则按优先级为:
| 条件 | 是否显示箭头 |
|---|---|
显式传 showArrow | 以传入值为准 |
传了自定义 arrow | 显示 |
传了 onPress / onLongPress | 显示 |
| 以上都没有 | 不显示 |
import { Cell } from '@skyroc/native-ui';
import { Alert, View } from 'react-native';
function handlePress(label: string) {
Alert.alert(label, '列表项已点击');
}
const CellPress = () => {
return (
<View className="bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
title="可点击列表项"
onPress={() => handlePress('可点击列表项')}
/>
<Cell
showArrow
subtitle="也可以通过 showArrow 显式控制"
title="显式显示箭头"
onPress={() => handlePress('显式显示箭头')}
/>
</View>
</View>
);
};
export { CellPress };不可点击的 Cell 也可以通过 showArrow 强制显示箭头,用于「箭头只作视觉提示、点击交给外层容器」的场景。
左侧内容
leading 放图标、头像等前置内容,容器带 mr-3 的右间距并垂直居中。
import { Cell, Text } from '@skyroc/native-ui';
import { View } from 'react-native';
const CellLeading = () => {
return (
<View className="bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
leading={
<View className="size-9 items-center justify-center rounded-xl bg-primary/10">
<Text className="text-sm font-semibold text-primary">A</Text>
</View>
}
subtitle="leading 可以承载图标"
title="图标入口"
/>
<Cell
leading={
<View className="size-9 items-center justify-center rounded-full bg-success/10">
<Text className="text-sm font-semibold text-success">林</Text>
</View>
}
title="头像入口"
trailing="在线"
/>
</View>
</View>
);
};
export { CellLeading };leading 内的文字颜色不会自动跟随 Cell:RN 的文字颜色不从父节点继承,图标组件也需要自己传 color 或使用 accent-* 类。
右侧内容与箭头方向
trailing 是右侧内容区,string 会包成弱化色的 Text(类名来自 trailingText slot)。arrowDirection 控制默认箭头的朝向,取值为 'right' | 'down' | 'up' | 'left',传了自定义 arrow 时该属性失效。
import { Cell } from '@skyroc/native-ui';
import { Alert, View } from 'react-native';
function handlePress(label: string) {
Alert.alert(label, '列表项已点击');
}
const CellArrow = () => {
return (
<View className="bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
showArrow
title="右箭头"
onPress={() => handlePress('右箭头')}
/>
<Cell
showArrow
arrowDirection="down"
title="下箭头"
trailing="展开"
onPress={() => handlePress('下箭头')}
/>
<Cell
showArrow
arrowDirection="up"
title="上箭头"
trailing="收起"
onPress={() => handlePress('上箭头')}
/>
</View>
</View>
);
};
export { CellArrow };默认箭头是 @expo/vector-icons 的 AntDesign 图标,颜色取自 arrowIcon slot 的 accent-muted-foreground,跟随主题 token 而不是硬编码灰值;尺寸随 size 缩放(见下表)。该 slot 不在 classNames 里开放,需要换色请传自定义 arrow。
分组
CellGroup 把多个 Cell 收成一张卡片:根节点为 overflow-hidden rounded-xl,title 作为分组标题渲染在卡片上方,border(默认 true)在相邻子项之间插入 h-px bg-border 的分隔线。
import { Cell, CellGroup } from '@skyroc/native-ui';
import { Alert, View } from 'react-native';
function handlePress(label: string) {
Alert.alert(label, '列表项已点击');
}
const CellGroupBasic = () => {
return (
<View className="bg-muted p-4">
<CellGroup
classNames={{ root: 'border border-border/70 bg-background' }}
title="账户设置"
>
<Cell
title="个人资料"
trailing="已完善"
/>
<Cell
title="安全设置"
trailing="正常"
/>
<Cell
showArrow
title="更多设置"
onPress={() => handlePress('更多设置')}
/>
</CellGroup>
</View>
);
};
export { CellGroupBasic };两点值得注意:
- 分隔线是容器插入的独立节点,不是往子元素上注入类名,所以子项可以是
Cell之外的任何组件;需要缩进时给classNames.divider传ml-*。 CellGroup的根节点只有圆角和裁剪,没有背景色。底色来自每个Cell自带的bg-background;要给卡片本身加底色或描边,通过classNames.root传。
内嵌分组
inset 给卡片加上 mx-4 的左右留边,形成 iOS 设置页那种悬浮卡片效果。分组标题保持 px-4,与卡片内容左对齐。
import { Cell, CellGroup } from '@skyroc/native-ui';
import { Alert, View } from 'react-native';
function handlePress(label: string) {
Alert.alert(label, '列表项已点击');
}
const CellGroupInset = () => {
return (
<View className="bg-muted py-4">
<CellGroup
inset
classNames={{ root: 'border border-border/70 bg-background' }}
title="通知设置"
>
<Cell
title="系统通知"
trailing="已开启"
/>
<Cell
title="活动提醒"
trailing="仅重要"
/>
<Cell
showArrow
title="通知偏好"
onPress={() => handlePress('通知偏好')}
/>
</CellGroup>
</View>
);
};
export { CellGroupInset };尺寸
size 同时决定行高、内边距、标题与副标题字号,以及默认箭头的像素大小:
| 尺寸 | 最小行高 | 横向内边距 | 纵向内边距 | 标题字号 | 副标题字号 | 右侧文字字号 | 箭头大小 |
|---|---|---|---|---|---|---|---|
sm | 40 | 12 | 8 | 14 | 10 | 12 | 11 |
md | 48 | 16 | 12 | 16 | 12 | 14 | 12 |
lg | 56 | 16 | 14 | 18 | 14 | 16 | 14 |
import { Cell } from '@skyroc/native-ui';
import { View } from 'react-native';
const CellSize = () => {
return (
<View className="bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
size="sm"
subtitle="Small"
title="紧凑尺寸"
/>
<Cell
size="md"
subtitle="Medium"
title="默认尺寸"
/>
<Cell
size="lg"
subtitle="Large"
title="宽松尺寸"
/>
</View>
</View>
);
};
export { CellSize };行高是 min-h-* 而不是固定高度,内容多行时会自然撑高。
对齐方式
center 默认为 true,leading / 内容区 / trailing / 箭头整体垂直居中。副标题较长导致内容换行时,传 center={false} 让各区域顶部对齐。
import { Cell } from '@skyroc/native-ui';
import { View } from 'react-native';
const CellCenter = () => {
return (
<View className="gap-3 bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
subtitle="默认 center 为 true,标题与右侧内容整体垂直居中,副标题较长时右侧文字会落在中间。"
title="居中对齐"
trailing="默认"
/>
</View>
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
center={false}
subtitle="center 传 false 后各区域顶部对齐,多行副标题的场景下右侧内容与标题在同一行。"
title="顶部对齐"
trailing="center=false"
/>
</View>
</View>
);
};
export { CellCenter };禁用
disabled 让整行降到 50% 不透明度,可点击时同时阻断 onPress / onLongPress 并把状态写进 accessibilityState。不可点击的 Cell 传 disabled 只有视觉效果。
import { Cell } from '@skyroc/native-ui';
import { Alert, View } from 'react-native';
function handlePress(label: string) {
Alert.alert(label, '列表项已点击');
}
const CellDisabled = () => {
return (
<View className="bg-muted p-4">
<View className="overflow-hidden rounded-2xl border border-border/70 bg-background">
<Cell
disabled
showArrow
subtitle="禁用后不会触发点击事件"
title="暂不可用"
trailing="Disabled"
onPress={() => handlePress('暂不可用')}
/>
</View>
</View>
);
};
export { CellDisabled };样式覆盖
Cell 没有 className,样式一律走 classNames:
| slot | 作用位置 |
|---|---|
root | 根节点(可点击时是 Pressable,否则是 View) |
leading | 左侧内容容器 |
content | 标题与副标题所在的中间区域 |
title | 标题文字(仅 title 为 string 时生效) |
subtitle | 副标题文字(仅 subtitle 为 string 时生效) |
trailing | 右侧内容容器 |
trailingText | 右侧文字(仅 trailing 为 string 时生效) |
arrow | 箭头容器 |
CellGroup 的 slot 为 root(卡片容器)、title(分组标题)、divider(分隔线)。
无障碍
可点击的 Cell 会设置 accessibilityRole="button",并把 disabled 映射到 accessibilityState.disabled;不可点击时不设置 role,读屏器按普通内容播报。title / subtitle 传自定义节点时读屏器只能读到节点内的文本,建议一并传 accessibilityLabel。
API
Cell
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| title | 标题,string 自动包裹 Text | ReactNode | - |
| subtitle | 副标题,string 自动包裹 Text | ReactNode | - |
| leading | 左侧区域内容,通常放图标或头像 | ReactNode | - |
| trailing | 右侧内容区域,string 自动包裹 Text | ReactNode | - |
| size | 尺寸,同时决定行高、内边距、字号与默认箭头大小 | 'sm' | 'md' | 'lg' | 'md' |
| center | 内容是否垂直居中,多行内容想顶部对齐时传 false | boolean | true |
| showArrow | 是否显示右侧箭头,缺省时由 arrow 与点击回调推导 | boolean | - |
| arrow | 自定义箭头内容,覆盖默认图标;传入即视为需要显示箭头 | ReactNode | - |
| arrowDirection | 默认箭头的方向,传了自定义 arrow 时无效 | 'right' | 'down' | 'up' | 'left' | 'right' |
| disabled | 禁用交互并整体降低透明度;可点击时同时阻断回调 | boolean | false |
| onPress | 点击回调,传入后根节点渲染为 Pressable | () => void | - |
| onLongPress | 长按回调,同样会让整行变成可点击的 Pressable | () => void | - |
| classNames | 覆盖各 slot 的类名 | SlotClassNames<CellSlots> | - |
| accessibilityLabel | 无障碍标签,未提供时读屏朗读子节点文本 | string | - |
| testID | 测试标识 | string | - |
| ref | 根节点的 ref,用于 measure / 滚动定位;可点击时根节点是 Pressable,实例类型同为 View | Ref<View> | - |
CellGroup
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| children* | 分组内容,通常为 Cell 组件 | ReactNode | - |
| title | 分组标题,string 自动包裹 Text | ReactNode | - |
| inset | 是否为卡片式内嵌样式(左右留边 mx-4) | boolean | false |
| border | 是否在相邻子项之间插入分隔线 | boolean | true |
| classNames | 覆盖各 slot 的类名,分隔线需要缩进时给 divider 传 ml-* | SlotClassNames<CellGroupSlots> | - |
| ref | 根节点的 ref,用于 measure / 滚动定位等命令式操作 | Ref<View> | - |
类型
import type { CellGroupProps, CellGroupSlots, CellProps, CellSize, CellSlots } from '@skyroc/native-ui';CellSize
Cell 尺寸,同时决定行高、内边距、字号与默认箭头大小。
CellSlots
Cell 可通过 classNames 覆盖的 slot 名称;箭头图标取色用的 arrowIcon 不在其中。
CellGroupSlots
CellGroup 可通过 classNames 覆盖的 slot 名称。
SlotClassNames
classNames 的取值形态:把 slot 名映射到类名,每个 slot 都可选。本页用到的 slot 见 CellSlots / CellGroupSlots。