
Ignite 的 ListItem 组件构建可交互、可定制的列表行完整指南【免费下载链接】igniteInfinite Reds battle-tested React Native project boilerplate, along with a CLI, component/model generators, and more! 9 years of continuous development and counting.项目地址: https://gitcode.com/GitHub_Trending/ig/igniteListItem是 Ignite 样板工程中用于在列表中渲染单行内容的样式化行组件既可以直接配合FlatList、SectionList使用也可以独立摆放。它内置了高度控制、上下分隔线、左右图标与自定义组件插槽、i18n 国际化文本等一整套能力且对外透明地继承了TouchableOpacity的全部交互能力。读完本文你将掌握ListItem的全部 Props、底层渲染原理以及如何将它无缝接入列表并做深度样式定制。组件定位与设计思路ListItem的核心目标很明确让列表里的一行这种高频 UI 变得声明式、可复用、可定制。官方文档对其定位的表述是用于在列表中显示单个条目能提供很大灵活性——既可以展示一段简单文本也可以承载多个可交互、自定义样式的复杂元素。从源码结构看ListItem.tsx 中组件的注释也印证了这一点A styled row component that can be used in FlatList, SectionList, or by itself.一个样式化行组件可用于 FlatList、SectionList 或单独使用。ListItem采用forwardRef实现把 ref 转发到最外层的View上源码第 109 行forwardRefView, ListItemProps这意味着父组件可以直接拿到行的原生节点方便做测量、动画等高级操作。它的内部渲染结构是三层嵌套View外层容器承载分隔线与 containerStyle └── TouchableOpacity / View交互层承载 style ├── ListItemAction左侧图标或自定义组件 ├── Text中间文本区 └── ListItemAction右侧图标或自定义组件这一分层设计让外框样式分隔线、容器背景与触摸区域样式按压反馈、行内布局可以分别定制是理解后续所有样式 Props 的关键。基础用法一行代码渲染列表项最简单的用法只指定高度即可得到一个空白的列表行ListItem height{50} /默认高度为56对应源码中height 56的默认值见 ListItem.tsx。在 Ignite 的演示工程 DemoListItem.tsx 中height的三种用法被并排展示ListItem topSeparator{translate(demoListItem:useCase.height.defaultHeight)}/ListItem ListItem topSeparator height{100} {translate(demoListItem:useCase.height.customHeight)} /ListItem值得注意的细节是源码中触摸层的样式为{ minHeight: height }ListItem.tsx即高度通过minHeight而非固定height实现。这意味着行的高度会根据文本内容自动撑高——当文本较长、换行后占据更多空间时行会自动变高height只是提供一个最小值保证。这也是演示用例中 Height determined by text content高度由文本内容决定这一场景能够成立的原因。分隔线topSeparator 与 bottomSeparator列表行之间的分隔线是最常见的视觉需求ListItem将其做成了两个独立开关Prop默认值作用topSeparatorfalse在行上方显示分隔线bottomSeparatorfalse在行下方显示分隔线ListItem topSeparator{true} bottomSeparator{true} /两个开关可以单独开启或同时开启演示工程中 Separators 用例就展示了仅顶部线顶部底部线仅底部线三种形态ListItem topSeparator{translate(demoListItem:useCase.separators.topSeparator)}/ListItem ListItem topSeparator bottomSeparator {translate(demoListItem:useCase.separators.topAndBottomSeparator)} /ListItem ListItem bottomSeparator {translate(demoListItem:useCase.separators.bottomSeparator)} /ListItem从源码看分隔线不是额外的边框元素而是直接绘制在外层View的borderTopWidth/borderBottomWidth上颜色取自主题调色板中的colors.separatorListItem.tsx。该颜色在 colors.ts 中被定义为palette.neutral300因此分隔线颜色会跟随主题的暗色/亮色模式自动切换无需额外处理。向行内填充内容text、tx、children 与 txOptionsListItem的中间区域是一个增强版Text组件因此它继承了Text的三种内容注入方式。text直接传入字符串ListItem textHello World /tx国际化文本键tx传入的是 i18n 的翻译键组件会在渲染时根据当前语言环境查找对应文案。演示工程中常见的写法如下ListItem txexample:helloWorld /children嵌套任意组件children允许你放入任意内容注意它们会被嵌套在Text组件内部ListItem height{100} TextSubtext/Text /ListItem由于 children 位于Text内部你甚至可以像演示工程那样做富文本嵌套——在一个Text里再用不同preset的Text拼接出粗体常规混排的效果ListItem Text Text presetbold{translate(demoListItem:useCase.passingContent.nestedChildren1)}/Text { } Text presetdefault {translate(demoListItem:useCase.passingContent.nestedChildren2)} /Text /Text /ListItemtxOptions翻译插值参数txOptions用于向翻译模板传参典型场景是 i18next 的插值interpolation。例如翻译文件里有helloWorld: Hello {{name}}!则可以这样使用ListItem txexample:helloWorld txOptions{{ name: John }} /在源码层面tx与txOptions会被透传给Text组件而Text内部通过translate(tx, txOptions)完成文案解析见 Text.tsx只有tx解析失败无对应键时才会回退到text或children。优先级为tx text children。文本样式定制textStyle 与 TextPropstextStyle文本样式覆盖textStyle直接作用于中间Text组件的样式。源码中文本样式的合成顺序为[$textStyle, $textStyleOverride, TextProps?.style]ListItem.tsx即内置样式 →textStyle覆盖 →TextProps.style最终覆盖。ListItem textHello World textStyle{{ color: red }} /内置的$textStyle包含三件事ListItem.tsxpaddingVertical: spacing.xs即 8px见 spacing.ts保证文本在行内上下有呼吸空间alignSelf: center文本在行内垂直居中flexGrow: 1, flexShrink: 1文本区占据左右图标之外的全部剩余宽度并允许在空间不足时收缩。TextProps透传所有 Text 属性TextProps可以把任意Text支持的属性直接透传进去——包括weight、size、preset、numberOfLines等ListItem textHello World TextProps{{ weight: bold }} /一个非常实用的组合是TextProps{{ numberOfLines: 1 }}当列表行的文案很长时可以强制单行显示。演示工程在高度由文本决定的用例中正是这样处理长文本的ListItem topSeparator bottomSeparator TextProps{{ numberOfLines: 1 }} {translate(demoListItem:useCase.height.longText)} /ListItem注意textStyle与TextProps.style都可以影响文本样式区别在于前者是ListItem为文本单独设计的快捷入口后者则是把整个TextProps对象整体透传——如果两者都传了TextProps.style优先级更高。两层容器样式containerStyle 与 style理解ListItem的样式体系关键是分清它的两层外壳containerStyle作用于外层 ViewcontainerStyle应用于最外层的View承载分隔线的容器。它适合设置整行的背景、边框、外边距等块级样式ListItem textHello World containerStyle{{ backgroundColor: red }} /从源码第 143-147 行可以看到外层容器样式的合成顺序是topSeparator分隔线 →bottomSeparator分隔线 →containerStyle覆盖。演示工程的 Styled Container (separators) 用例就通过containerStyle给行加了 5px 的自定义顶边框const $customContainerStyle: ThemedStyleViewStyle ({ colors }) ({ borderTopWidth: 5, borderTopColor: colors.palette.neutral100, })style作用于 TouchableOpacitystyle应用于内层的TouchableOpacity触摸层合成顺序为[$styles.row, $touchableStyle, { minHeight: height }, style]ListItem.tsx。其中$styles.row来自全局的 styles.ts提供flexDirection: row基础布局$touchableStyle内置alignItems: flex-start使左右图标与文本在行内顶部对齐。ListItem textHello World style{{ backgroundColor: red }} /两者的组合用法从演示工程的 Styling 用例可以清楚看到三者的叠加效果——当需要同时定制文本、触摸层和外层容器时ListItem topSeparator textStyle{{ color: theme.colors.palette.neutral100 }} style{themed($customTouchableStyle)} // 触摸层背景 containerStyle{themed($customContainerStyle)} // 外层边框 rightIconladybug leftIconladybug rightIconColor{theme.colors.palette.neutral100} leftIconColor{theme.colors.palette.neutral100} {translate(demoListItem:useCase.styling.tintedIcons)} /ListItem左右图标leftIcon、rightIcon 与颜色leftIcon和rightIcon让你用一行代码在行的两侧放上图标。图标名必须来自Icon组件的iconRegistry注册表Icon.tsx可用的键包括back、bell、caretLeft、caretRight、check、hidden、ladybug、lock、menu、more、settings、view、x等演示用的clap、community、components、debug、github、heart、pin、podcast、slack在移除演示代码时会被一并清理。ListItem textHello World leftIconbell rightIconbell /图标颜色通过leftIconColor/rightIconColor独立控制ListItem textHello World leftIconbell leftIconColorred rightIconbell rightIconColorred /从源码看图标尺寸固定为 24px图标外层容器高度被设置为行高size{height}并垂直水平居中ListItem.tsx左右图标分别通过marginEnd: spacing.md/marginStart: spacing.md即 16px与文本区隔开ListItem.tsx。一个典型的真实场景是把rightIconcaretRight用作更多/下一级的指示符——演示工程的 FlatList 集成用例正是这么做的。完全自定义侧边LeftComponent 与 RightComponent当图标无法满足需求时LeftComponent/RightComponent允许你传入任意ReactElement替换左侧或右侧区域且优先级高于对应侧的图标——从源码第 190 行if (Component) return Component可以看出只要传入了Component同侧icon就会被忽略。ListItem textHello World LeftComponent{TextLeft/Text} RightComponent{TextRight/Text} /这是ListItem灵活性的天花板演示工程用它实现了一个由 9 个瓢虫图标ladybug平铺组成的自定义左侧区域配合主题样式ListItem topSeparator LeftComponent{ View style{themed([$styles.row, $customLeft, { marginEnd: theme.spacing.md }])} {Array.from({ length: 9 }, (x, i) i).map((i) ( Icon key{i} iconladybug color{theme.colors.palette.neutral100} size{20} / ))} /View } {translate(demoListItem:useCase.customLeftRight.customLeft)} /ListItem注意两侧自定义组件的 Props 名是大写开头的LeftComponent/RightComponent与leftIcon的小写风格不同使用时不要写错。交互能力继承 TouchableOpacity 的一切ListItem本质上是一个可交互的组件——它内部包含了TouchableOpacity因此除了上述自定义 Props 之外所有TouchableOpacity合法 Props 都可以直接传入包括onPress、onPressIn、onPressOut、onLongPress、disabled、activeOpacity、hitSlop等。ListItem textSettings leftIconsettings rightIconcaretRight onPress{() navigation.navigate(Settings)} /更精巧的是源码实现了一个智能包装逻辑ListItem.tsx组件会检测是否传入了任一触摸回调onPress、onPressIn、onPressOut、onLongPress只有存在触摸回调时才渲染TouchableOpacity否则退化为普通的Viewconst isTouchable TouchableOpacityProps.onPress ! undefined || TouchableOpacityProps.onPressIn ! undefined || TouchableOpacityProps.onPressOut ! undefined || TouchableOpacityProps.onLongPress ! undefined const Wrapper isTouchable ? TouchableOpacity : View这一设计带来两个实际收益其一纯展示型列表行不会白白挂载TouchableOpacity渲染更轻量其二行为是自解释的——传入onPress即可点不传则自动是静态行无需手动切换组件。实战在 FlatList / SectionList 中集成ListItem最常见的使用场景就是作为列表的renderItem。由于它自带分隔线能力配合 FlatList 时甚至可以省略ItemSeparatorComponent。演示工程 DemoListItem.tsx 中给出了完整范例const listData ...长文本....split(.).map((item) item.trim()) FlatListstring data{listData} keyExtractor{(item, index) ${item}-${index}} renderItem{({ item, index }) ( ListItem text{item} rightIconcaretRight TextProps{{ numberOfLines: 1 }} topSeparator{index ! 0} // 首行不显示分隔线其余行显示 / )} /这段代码展示了两个高频技巧用topSeparator{index ! 0}精确控制首行无分隔线、后续行有分隔线的经典列表形态用TextProps{{ numberOfLines: 1 }}保证超长文案不破坏行高。SectionList的用法完全一致——把ListItem放入renderItem即可左侧图标、右侧箭头、分隔线等能力开箱即用。主题适配一行样式全主题生效ListItem的所有内部样式分隔线、文本、图标间距都是通过useAppTheme()的themed()包装的主题化样式ThemedStyle因此亮色/暗色模式切换时颜色自动跟随不需要任何额外代码。例如分隔线颜色colors.separator在暗色主题下会自动切换为对应的暗色值。如果你想基于主题做定制演示工程的模式值得参考——把自定义样式定义为ThemedStyle渲染时用themed($customStyle)包裹const $customTextStyle: ThemedStyleTextStyle ({ colors }) ({ color: colors.error, }) // 使用 ListItem topSeparator textStyle{themed($customTextStyle)} {translate(demoListItem:useCase.styling.styledText)} /ListItem这也解释了为何textStyle、style、containerStyle虽然接收的是普通的StyleProp却能与主题体系无缝协作——themed()在调用侧完成主题注入组件内部只负责样式合成。源码速览完整的 Props 清单最后将 ListItem.tsx 中定义的完整 Props 汇总如下全部继承自TouchableOpacityPropsProps类型默认值说明heightnumber56行高通过minHeight生效文本可撑高topSeparatorbooleanfalse是否显示顶部 1px 分隔线bottomSeparatorbooleanfalse是否显示底部 1px 分隔线textTextProps[text]—直接显示的文本优先级低于txtxTextProps[tx]—i18n 翻译键childrenTextProps[children]—嵌套在Text内的子元素txOptionsTextProps[txOptions]—翻译插值参数textStyleStylePropTextStyle—文本样式覆盖TextPropsTextProps—完整透传给内部Text的属性containerStyleStylePropViewStyle—外层View样式含分隔线容器styleStylePropViewStyle—内层TouchableOpacity样式leftIconIconTypes—左侧图标注册表内名称leftIconColorstring—左侧图标颜色rightIconIconTypes—右侧图标注册表内名称rightIconColorstring—右侧图标颜色LeftComponentReactElement—自定义左侧元素覆盖leftIconRightComponentReactElement—自定义右侧元素覆盖rightIcon想查看全部用法示例可以运行演示工程在 DemoShowroom 的ListItem栏目中交互体验上述全部能力对应源码位于 DemoListItem.tsx演示文案定义在 demo-en.ts并已同步翻译为阿拉伯语、西班牙语、法语、印地语、日语、韩语等多语言版本其余如Text、Icon等配套组件文档可在 docs/boilerplate/app/components 目录中继续深入阅读。【免费下载链接】igniteInfinite Reds battle-tested React Native project boilerplate, along with a CLI, component/model generators, and more! 9 years of continuous development and counting.项目地址: https://gitcode.com/GitHub_Trending/ig/ignite创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考