☰
在React Native和Expo中使用blobatar:为什么size必填、为什么没有animate?
2026/10/12 9:59:24 网站建设 项目流程

【免费下载链接】blobatar

项目地址:https://gitcode.com/gh_mirrors/bl/blobatar
点击查看免费下载

blobatar是一个零依赖、确定性几何头像库:给它任何字符串(用户名、邮箱、用户 ID),就能生成一个独一无二、且每次渲染都完全一致的卡通头像。当你在React Native或Expo项目中使用@blobatar/react-native适配器时,会发现它和 Web 端 adapter 有两个"反直觉"的差异——size变成了必填项,而animate属性整个消失了。

这不是 bug,而是平台差异倒逼出的设计取舍。这篇文章带你快速上手安装与使用,并讲清楚这两个"为什么"。

先认识一下 blobatar 头像

blobatar 从任意字符串生成确定性几何头像:同样的字符串永远渲染同一个 blobatar,不同字符串几乎必然长得不一样——没有头像上传、没有服务端、没有随机数。

核心包只有约 4.4 KB(gzip),头像只由<Path>和<Circle>这类基础图形构成,没有渐变、滤镜或遮罩——这一点直接决定了 React Native 适配器的实现方式。

一键安装:@blobatar/react-native 在 Expo 中无需额外配置

安装只需两条命令:

bun add @blobatar/react-native blobatar npx expo install react-native-svg

react-native-svg是它的 peer dependency,也是真正负责绘制的一方。Expo 应用不需要@blobatar/expo——Expo 应用本质就是 React Native 应用,两边用的是同一个react-native-svg,所以官方明确说明不会有单独的 Expo 包。

最基础的用法就一行:

import { Blobatar } from "@blobatar/react-native"; <Blobatar name="username" size={48} />;

注意这里必须同时传name和size。为什么?往下看。

为什么 size 必填:React Native 没有 CSS 兜底

在 Web 端,size是可选项。省略它时,不输出width/height,让 CSS 去决定元素大小,viewBox会随页面布局自动缩放——页面想要多大就多大。

React Native 没有这样的兜底机制:

  • 这里没有 CSS 布局系统替你"顺便"定尺寸;
  • 一个没有尺寸的<Svg>最好情况是大小不明确,最坏情况就是一块空白。

设计者其实考虑过给一个默认值,但拒绝了这个方案,理由写在 packages/react-native/src/parts.tsx 的类型注释里:

一个默认 size 就是一个会改变画面的默认值;默认值只允许写在核心包一处。适配器如果擅自发明默认值,等于偷换了画面。

所以适配器选择把平台差异变成调用处的编译错误,而不是运行时的空白方块:你忘传size,TypeScript 立刻报错,而不是在手机上看到一片空白。这是"fail fast"胜过"静默失败"的典型例子。

为什么没有 animate:运动层是 CSS,而 RN 没有 CSS

在 Web 端,animate属性(取值"hover"/"always")开启 idle 层动画:呼吸、上下浮动、眨眼、环顾。但 Web 上的 idle 层本质上是一套样式表——motion.css、一个根 class、一组带种子的 CSS 自定义属性。

React Native 三样都没有。于是官方做了个干脆的决定:animate从类型定义中直接缺席,而不是"接受但忽略"。传错就是编译错误,错误信息里会点明这个包的名字——这是让你学到"平台差异"最便宜的地方。

那动画能力去哪了?它被拆成了三个组件、三个层级,按需引入:

组件来源能力
Blobatar包根路径静态头像,最省字节
MorphingBlobatar包根路径在两个expression之间做 300ms 渐变
AnimatedBlobatar@blobatar/react-native/animated在 morph 之上再加 idle 层(呼吸、眨眼等)

每个层级是独立导出,打包器会自动丢掉你从未 import 的组件——静态头像列表页一个动画字节都不用带。这个"组件分层代替开关属性"的设计动机和完整变更记录,可以查看 packages/react-native/CHANGELOG.md。

expression 完全可用:把表情作为值导入

expression在这个适配器上完整可用。静态表情会被直接"烘焙"进几何形状里(bake into the geometry),所以它不需要 CSS 也能工作:

import { happy } from "blobatar/expression"; <Blobatar name="username" size={48} expression={happy} />;

想要表情切换时平滑过渡而不是"切"过去,就换用MorphingBlobatar——props 完全相同:

<MorphingBlobatar name="username" size={48} expression={busy ? sad : happy} />;

渐变时长是 300ms(切换表情)和 400ms(回到 idle),和 Web 端同一套曲线;中途切换新表情会从"脸当前实际所在的位置"继续,不会跳变。

blobatar 全部 10 种轮廓、8 档色相、14 种表情和 4 种背景一览如下,方便你确认expression可以取哪些值:

AnimatedBlobatar 用法:animate 变成由你驱动的布尔值

如果你确实需要 idle 层的"活"的感觉,用独立入口引入AnimatedBlobatar:

npx expo install react-native-reanimated react-native-worklets
import { AnimatedBlobatar } from "@blobatar/react-native/animated"; // 个人主页:一个大头像,常开 <AnimatedBlobatar name="ada" size={120} animate />; // 网格:只让列表告诉你"在屏幕上"的那个动 <AnimatedBlobatar name={u.id} size={44} animate={visible.has(u.id)} />;

这里有几个关键点:

  • animate是布尔值且默认false。Web 端 idle 层挂在:hover上,而触摸屏没有 hover——所以"什么时候动"变成了只有你的 App 能回答的问题:屏幕焦点、列表可视性、用户偏好……
  • 循环跑在 UI 线程(Reanimated worklets),一屏头像同时呼吸也不会给 JS 线程造成逐帧渲染压力;
  • 只有/animated子路径需要这两个原生依赖,Blobatar和MorphingBlobatar依然零动画依赖。

⚠️Expo 用户特别注意:

  1. 用npx expo install而不是npm install安装 reanimated/worklets——worklets 的 JS 部分和原生部分必须精确匹配,Expo 上原生部分由 SDK 编译进应用,版本不对会在首次渲染抛出Mismatch between JavaScript part and native part;
  2. react-native-reanimated是原生模块,需要development build,Expo Go 跑不了。

无障碍与减少动态效果

react-native-svg没有<title>元素,所以titleprop 会被映射为根<Svg>上的无障碍标签(accessible、accessibilityLabel、accessibilityRole="image")。不传的话,头像树对屏幕阅读器隐藏——等价于 Web 上的aria-hidden。

这个包刻意不 import 任何react-native模块(见 packages/react-native/src/index.tsx 的头部注释),因此它自己读不到系统的"减弱动态效果"设置。好消息是你的 App 本来就能读到:

import { AccessibilityInfo } from "react-native"; const reduce = AccessibilityInfo.useReduceMotionEnabled(); <AnimatedBlobatar name="username" size={48} animate={!reduce} />;

小结:两个"不同"都是平台的锅

差异根本原因设计选择
size必填RN 没有 CSS 兜底,无尺寸 = 空白必填 prop,把问题变成编译错误
没有animate属性idle 层是 CSS 样式表,RN 没有拆成 3 个组件按需引入,animate仅存在于AnimatedBlobatar且由你驱动

更多细节(MorphingBlobatar的中断语义、seed 时序如何在两端保持一致等)建议直接阅读官方适配器文档 packages/react-native/README.md,以及解释"为什么每个框架适配器都是独立包"的架构决策记录 docs/adr/0009-adapters-as-their-own-packages.md。

上手路径很简单:装好react-native-svg,给name和size,静态头像立刻能用;想要表情就上MorphingBlobatar;想要"活着"的感觉,再用/animated入口加一个布尔值。🎉

【免费下载链接】blobatar

项目地址:https://gitcode.com/gh_mirrors/bl/blobatar
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询