Ignite 的 Icon 与 PressableIcon 组件:内置图标注册表、Props 详解与自定义图标实战
【免费下载链接】igniteInfinite Red's 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
本篇技术指南围绕 Infinite Red 开源项目 Ignite 的 React Native 样板代码(boilerplate)中预置的Icon与PressableIcon组件展开,讲解它们如何基于"预定义图标图片 + 注册表"完成图标渲染,逐一说明icon、color、size、style、containerStyle、onPress等 Props 的语义与用法,并结合组件源码与 Showroom 演示代码,给出在Header、ListItem、Button、导航栏等真实场景中的组合用法,以及新增自定义图标的完整操作流程。读完本文,你将能够直接在本项目的任意界面中渲染、着色、缩放和包装图标,并能将自有的 PNG 素材接入 Ignite 的图标体系。
一、组件定位:一个注册表驱动的图片型图标方案
Ignite 的图标方案不是使用字体图标(icon font),而是图片型图标:所有图标都是项目assets/icons/目录下的 PNG 图片,通过iconRegistry这个"名称 → require 资源"的映射注册表统一管理。
在 Icon.tsx 中,这一体系由两个对外组件和一个注册表对象构成:
Icon:将图标图片包裹在 React Native 的View中渲染,适合纯展示场景;PressableIcon:将同一张图片包裹在TouchableOpacity中渲染,并透传onPress,适合可点击的图标按钮;iconRegistry:以字符串名为键、以require(...)图片资源为值的注册表对象,同时导出了类型IconTypes = keyof typeof iconRegistry,保证传入的icon名称有 TypeScript 类型约束(Icon.tsx)。
<Icon icon="debug" /><PressableIcon icon="ladybug" onPress={() => Alert.alert("Hello")} />两个组件共享同一套BaseIconProps(icon、color、size、style、containerStyle),差异仅在于外层容器与继承的 React Native 组件类型:PressableIconProps = Omit<TouchableOpacityProps, "style"> & BaseIconProps,IconProps = Omit<ViewProps, "style"> & BaseIconProps(Icon.tsx)。因此,除了下文列出的自有 Props 外,你可以把TouchableOpacity(用于PressableIcon)或View(用于Icon)支持的任何 Props 透传进去,它们会被转发到对应的外层容器组件。
二、内置图标注册表:可用的 19 个图标名称
icon是必填的 Props,值为注册表中的字符串名。以下名称来自 Icon.tsx 中iconRegistry的实际定义,其中标注// @demo remove-current-line的条目属于演示(demo)专用图标,执行 Ignite CLI 的remove-demo命令后会被自动移除:
| 图标名称 | 对应图片资源 | 说明 |
|---|---|---|
back | @assets/icons/back.png | 返回箭头 |
bell | @assets/icons/bell.png | 铃铛/通知 |
caretLeft | @assets/icons/caretLeft.png | 左箭头 |
caretRight | @assets/icons/caretRight.png | 右箭头 |
check | @assets/icons/check.png | 对勾 |
clap | @assets/icons/demo/clap.png | 鼓掌(demo) |
community | @assets/icons/demo/community.png | 社区(demo) |
components | @assets/icons/demo/components.png | 组件(demo) |
debug | @assets/icons/demo/debug.png | 调试(demo) |
github | @assets/icons/demo/github.png | GitHub 标志(demo) |
heart | @assets/icons/demo/heart.png | 爱心(demo) |
hidden | @assets/icons/hidden.png | 隐藏 |
ladybug | @assets/icons/ladybug.png | 瓢虫(演示中最常用) |
lock | @assets/icons/lock.png | 锁 |
menu | @assets/icons/menu.png | 菜单 |
more | @assets/icons/more.png | 更多 |
pin | @assets/icons/demo/pin.png | 图钉(demo) |
podcast | @assets/icons/demo/podcast.png | 播客(demo) |
settings | @assets/icons/settings.png | 设置 |
slack | @assets/icons/demo/slack.png | Slack 标志(demo) |
view | @assets/icons/view.png | 眼睛/查看 |
x | @assets/icons/x.png | 关闭 |
<Icon icon="bell" />由于IconTypes直接由keyof typeof iconRegistry推导,如果你传入一个不存在的名称,TypeScript 会在编译期报错,这是该方案相比字符串硬编码更安全的一点。Showroom 的 DemoIcon.tsx 会遍历Object.keys(iconRegistry)并把全部图标平铺展示(每个size={35}、着色theme.colors.tint、下方标注图标名),运行时运行 demo 即可直观核对所有可用图标。
2.1 每个图标的基础图片
所有内置图标均以@1x、@2x、@3x三种分辨率存放在boilerplate/assets/icons/目录(如ladybug.png24x24、ladybug@2x.png48x48、ladybug@3x.png72x72),由 React Native 的图片加载机制按屏幕像素密度自动选取。未显式传入size时,图标按图片原始分辨率渲染。
三、Props 全解:从基础渲染到样式覆写
3.1color:一键改色的 tintColor
color是可选字符串,用于设置图标图片的tintColor(React Native 图片样式属性),实现对单色 PNG 的重新着色。
<Icon icon="x" color="#7C7C7C" />从源码看,未传color时组件会自动取当前主题的文字色作为默认着色:
const { theme } = useAppTheme() const $imageStyle: StyleProp<ImageStyle> = [ $imageStyleBase, { tintColor: color ?? theme.colors.text }, ... ]这一默认行为在 Icon.tsx(PressableIcon)与 Icon.tsx(Icon)中完全一致——组件通过useAppTheme()读取主题,浅色/深色模式下无需额外传参即可获得正确的前景色。
实战中常见的做法是结合主题调色板(palette)传色,例如 DemoIcon.tsx 用同一只瓢虫展示了 5 种调色板配色(accent500、primary500、secondary500、neutral700、angry500)。这些颜色均定义于 colors.ts 的palette常量。导航场景则更常见的是按选中态切换颜色,见 DemoNavigator.tsx:
<Icon icon="podcast" color={focused ? colors.tint : colors.tintInactive} size={30} />3.2size:统一缩放图标尺寸
size是可选数字,同时设定图标图片的宽高:
<Icon icon="x" size={24} />源码中的实现是条件式覆写:size !== undefined && { width: size, height: size }(Icon.tsx)。即不传size时保持图片原始分辨率,传入后强制等比例缩放到指定边长。DemoIcon.tsx 用ladybug展示了不传size与size={35}、size={50}、size={75}四种形态的对比。
3.3style:覆写图标图片自身样式
style是可选对象,类型为StyleProp<ImageStyle>,用于覆写图标图片的样式。默认基础样式仅设置resizeMode: "contain"(Icon.tsx),确保图标在容器内等比完整显示、不被裁切。
<Icon icon="ladybug" style={{ width: 20, height: 20 }} />需要注意:style直接作用于<Image>($imageStyleBase、tintColor、size计算值会与$imageStyleOverride合并),而width/height的覆写优先级高于size的计算值。ImageStyle支持tintColor、resizeMode、transform等属性;Header.tsx 就利用style在 RTL 布局下对返回箭头做了 180° 旋转:
style={isRTL ? { transform: [{ rotate: "180deg" }] } : {}}3.4containerStyle:覆写外层容器样式
containerStyle是可选对象,类型为StyleProp<ViewStyle>,设置的是外层容器(TouchableOpacity或View)的样式。这在需要给图标加背景、padding、边框或整体布局对齐时非常有用:
<Icon icon="bug" containerStyle={{ backgroundColor: "red" }} />源码中容器样式作为整个style传给外层组件:<TouchableOpacity {...pressableProps} style={$containerStyleOverride}>(Icon.tsx)。需要注意containerStyle会完全替换而非合并默认容器样式,因此 Header 内部将其与主题样式合并后再传入:containerStyle={themed([$actionIconContainer, { backgroundColor }])}。
3.5onPress:让图标可点击
onPress仅适用于PressableIcon,会被转发到内层TouchableOpacity的onPress上:
<PressableIcon icon="ladybug" onPress={() => Alert.alert("Hello")} />四、真实场景:Icon 与其它组件的组合用法
4.1 Header 的左右操作按钮
Header.tsx 中,HeaderAction在未提供文字操作时直接渲染PressableIcon,并将icon、color、onPress、containerStyle全部透传,形成典型的"返回/更多"图标按钮:
<PressableIcon size={24} icon={icon} color={iconColor} onPress={onPress} containerStyle={themed([$actionIconContainer, { backgroundColor }])} style={isRTL ? { transform: [{ rotate: "180deg" }] } : {}} />4.2 ListItem 的左右图标
ListItem.tsx 的ListItemAction使用Icon渲染列表项左侧/右侧图标,并借助containerStyle传入图标容器边距与行高对齐:
<Icon size={24} icon={icon} color={iconColor} containerStyle={themed([ $iconContainerStyles, side === "left" && $iconContainerLeft, side === "right" && $iconContainerRight, { height: size }, ])} />4.3 Button 的 Accessory 图标
Button.tsx 通过LeftAccessory/RightAccessory接收渲染函数,demo 中在函数内返回Icon,并借用 props 传入的containerStyle完成定位,实现"图标 + 文字"按钮:
<Button preset="reversed" RightAccessory={(props) => ( <Icon containerStyle={props.style} style={$iconStyle} icon="ladybug" /> )} > {translate("demoButton:useCase.passingContent.multiLine")} </Button>4.4 TextField 的辅助图标
TextField.tsx 的文档注释同样示范了将Icon用作输入框右/左辅助图标,并根据可编辑状态切换颜色:
RightAccessory={(props) => ( <Icon icon="ladybug" containerStyle={props.style} color={props.editable ? colors.textDim : colors.text} /> )}五、自定义图标:三步接入新的图标资源
内置图标不够用时的扩展流程在 Icon.md 文档 中已有说明,结合源码可以归纳为三步:
第一步:放置图片资源。将图标 PNG 放到assets/icons/目录(demo 图标放assets/icons/demo/):
-- icon/ -- icons/ -- index.ts -- my-custom-icon.png第二步:注册到iconRegistry。在 Icon.tsx 的iconRegistry对象中新增一条记录:
export const iconRegistry = { // ... custom: require("./myCustomIcon.png"), }注册的同时,IconTypes类型会自动包含"custom",无需手动维护类型。项目使用@assets/icons这样的路径别名(在tsconfig.json/babel.config.js中配置),因此注册时也可以写require("@assets/icons/myCustomIcon.png")。
第三步:通过iconprop 使用。
<Icon icon="custom" /><PressableIcon icon="custom" onPress={() => Alert.alert("I'm a custom PressableIcon!")} />此后该图标即可在Header、ListItem、Button、TextField、导航栏等所有接受IconTypes的场景中直接引用,并同样支持color、size、style、containerStyle的全部能力。// @demo remove-current-line这类标记仅用于演示图标,普通自定义图标不加该注释即可被remove-demo流程保留。
六、小结
Ignite 的Icon/PressableIcon组件以"图片资源 +iconRegistry注册表 + 类型推导"为核心:icon从注册表取图,color经tintColor一键着色(默认取主题文字色),size等比缩放,style/containerStyle分别覆写图片与容器样式,PressableIcon额外提供TouchableOpacity的点击能力。配套的 DemoIcon.tsx 是完整的可运行示例(遍历全部图标、size 渐变、palette 配色、样式覆写四组用例),任何新图标只需"放图 + 注册"即可全局复用。该方案不引入字体文件与外部图标库依赖,图标即素材,风格完全可控,适合作为团队统一图标资产的落地方式。
【免费下载链接】igniteInfinite Red's 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),仅供参考