RollingText
数字 / 文本翻滚动画
翻滚文本(RollingText)把数字或文本按列逐字符滚动到目标值,常用于计数、榜单名次、抽奖开奖。每一列是一条独立的字符序列,各列只错开起跑时间、不改变时长,因此看上去是依次落定。
import { RollingText } from '@skyroc/native-ui';基础用法
数字模式下 targetNum 是目标值,列数由它的位数决定;startNum 是首次播放的起点。默认挂载后自动播放。
import { RollingText } from '@skyroc/native-ui';
import { View } from 'react-native';
const RollingTextBasic = () => {
return (
<View className="bg-background items-center px-4 py-6">
<RollingText
startNum={0}
targetNum={123}
/>
</View>
);
};
export { RollingTextBasic };targetNum 的异常值会被归一化:负数取绝对值、小数向零取整、非有限值退化为 0、超过 Number.MAX_SAFE_INTEGER 按上限处理 —— 1e21 这类值 String 出来是 "1e+21",逐位拆开会滚出一列乱码。
何时使用
- 数值变化需要被看见:积分、金额、在线人数。
- 开奖、抽签这类「逐位落定」的仪式感场景(用
textList文本模式)。 - 纯展示的静态数字请直接用
Text。
滚动方向
direction 控制字符向下(默认)或向上滚入,两种方向的目标值计算完全一致。
import { RollingText, Text } from '@skyroc/native-ui';
import { View } from 'react-native';
const RollingTextDirection = () => {
return (
<View className="flex-row justify-around bg-background px-4 py-6">
<View className="items-center gap-2">
<Text color="muted">direction="down"</Text>
<RollingText
direction="down"
startNum={0}
targetNum={123}
/>
</View>
<View className="items-center gap-2">
<Text color="muted">direction="up"</Text>
<RollingText
direction="up"
startNum={0}
targetNum={456}
/>
</View>
</View>
);
};
export { RollingTextDirection };停止顺序
stopOrder 决定哪一列先停:ltr 左列先起跑也先停(默认),rtl 反之。delayStep 是相邻两列的启动间隔(默认 200ms),两者共同决定错落效果。
import { RollingText, Text } from '@skyroc/native-ui';
import { View } from 'react-native';
const RollingTextStopOrder = () => {
return (
<View className="flex-row justify-around bg-background px-4 py-6">
<View className="items-center gap-2">
<Text color="muted">ltr</Text>
<RollingText
delayStep={300}
startNum={0}
stopOrder="ltr"
targetNum={123}
/>
</View>
<View className="items-center gap-2">
<Text color="muted">rtl</Text>
<RollingText
delayStep={300}
startNum={0}
stopOrder="rtl"
targetNum={789}
/>
</View>
</View>
);
};
export { RollingTextStopOrder };onFinish 只由最后落定的那一列触发一次,不会每列各报一次。
动画节奏
| 属性 | 含义 | 默认值 |
|---|---|---|
circles | 数字模式下每列额外空转的圈数,夹在 0 ~ 10 | 2 |
duration | 单列滚动时长(毫秒),不含 delayStep 的错峰耗时 | 2000 |
height | 每个字符所占的行高,字符的 lineHeight 跟随此值 | 40 |
import { RollingText } from '@skyroc/native-ui';
import { View } from 'react-native';
const RollingTextDuration = () => {
return (
<View className="bg-background items-center px-4 py-6">
<RollingText
circles={0}
delayStep={400}
duration={1200}
height={48}
startNum={0}
targetNum={9999}
/>
</View>
);
};
export { RollingTextDuration };各列共用同一个 duration,因此序列更长的列滚得更快 —— 这样它们才会按 stopOrder 的节奏依次停下,而不是长的那列拖到最后。
文本模式
传 textList 即进入文本模式:首项是起始态、末项是最终态,依次滚过中间各项。列数取最长一项,短项在多出的列上留空。文本模式下 targetNum / startNum / circles 不可用(类型上就是 never)。
import { Button, RollingText } from '@skyroc/native-ui';
import type { RollingTextRef } from '@skyroc/native-ui';
import { useRef } from 'react';
import { View } from 'react-native';
const RollingTextTextMode = () => {
const textRollingRef = useRef<RollingTextRef>(null);
return (
<View className="bg-background items-center px-4 py-6">
<RollingText
ref={textRollingRef}
textList={['', '处理中', '已完成']}
/>
<View className="mt-3 flex-row gap-2">
<Button
size="sm"
variant="outline"
onPress={() => textRollingRef.current?.reset()}
>
重新播放
</Button>
</View>
</View>
);
};
export { RollingTextTextMode };手动控制与完成事件
autoStart={false} 时挂载后停在起始位置,由 ref 驱动:
| 方法 | 说明 |
|---|---|
start() | 从起始位置播放一次;播放中调用会立即重播 |
reset() | 回到起始位置;autoStart 为 true 时立即重播,否则停在起点 |
import { Button, RollingText, Text } from '@skyroc/native-ui';
import type { RollingTextRef } from '@skyroc/native-ui';
import { useRef, useState } from 'react';
import { View } from 'react-native';
const RollingTextManual = () => {
const rollingRef = useRef<RollingTextRef>(null);
const [finishCount, setFinishCount] = useState(0);
function handleFinish() {
setFinishCount(current => current + 1);
}
function reset() {
rollingRef.current?.reset();
}
function start() {
rollingRef.current?.start();
}
return (
<View className="bg-background items-center px-4 py-6">
<RollingText
ref={rollingRef}
autoStart={false}
startNum={0}
targetNum={5678}
onFinish={handleFinish}
/>
<Text
className="mt-2"
color="muted"
>
onFinish 次数:{finishCount}
</Text>
<View className="mt-3 flex-row gap-2">
<Button
size="sm"
onPress={start}
>
开始
</Button>
<Button
size="sm"
variant="outline"
onPress={reset}
>
重置
</Button>
</View>
</View>
);
};
export { RollingTextManual };onFinish 在最后一列落定时触发一次;被下一轮播放打断则不触发。
动态目标值
targetNum 变化后从上一轮的终点继续往下滚,而不是闪回 startNum 再来一遍。位数增加或减少时整排列会重建(key 带上列数),不会复用按旧行高定位的动画值;列数只看目标值,所以数值变短不会留下一排前导零。
import { Button, RollingText, Text } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';
const TARGETS = [8, 42, 2026, 7];
const RollingTextDynamic = () => {
const [targetIndex, setTargetIndex] = useState(0);
const targetNum = TARGETS[targetIndex];
function changeTarget() {
setTargetIndex(current => (current + 1) % TARGETS.length);
}
return (
<View className="items-center gap-3 bg-background px-4 py-6">
<RollingText targetNum={targetNum} />
<Text color="muted">targetNum:{targetNum}</Text>
<Button
size="sm"
variant="outline"
onPress={changeTarget}
>
切换目标值
</Button>
</View>
);
};
export { RollingTextDynamic };还没播过时(autoStart={false} 且没手动 start)改 targetNum 只换终点、不起跑。
样式覆盖
className 追加到根容器上,classNames 按 slot 细粒度覆盖:
| slot | 作用位置 |
|---|---|
root | 根容器(横向排布) |
text | 每个滚动字符的文字类名 |
import { RollingText } from '@skyroc/native-ui';
import { View } from 'react-native';
const RollingTextStyles = () => {
return (
<View className="items-center bg-background px-4 py-6">
<RollingText
className="gap-1 rounded-xl bg-primary/10 px-3"
classNames={{ text: 'text-2xl font-bold text-primary' }}
height={48}
startNum={100}
targetNum={2026}
/>
</View>
);
};
export { RollingTextStyles };改字号时记得同步调 height:行高由 height 决定,字号和行高对不上会看到字符被裁切。
API
RollingText
RollingTextProps 是数字模式与文本模式的联合:传了 textList 即文本模式,此时 targetNum / startNum / circles 不可用。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| targetNum | 目标数字(数字模式必填),列数由位数决定;负数取绝对值、小数向零取整 | number | - |
| startNum | 首次播放的起点;之后以上一轮终点为起点 | number | 0 |
| circles | 每列额外空转的圈数,夹在 0 ~ 10 | number | 2 |
| textList | 文本模式的文本序列,首项为起始态、末项为最终态;列数取最长一项 | string[] | - |
| direction | 滚动方向 | 'down' | 'up' | 'down' |
| stopOrder | 停止顺序,ltr 为左列先停 | 'ltr' | 'rtl' | 'ltr' |
| delayStep | 相邻两列的启动间隔(毫秒) | number | 200 |
| duration | 单列滚动时长(毫秒) | number | 2000 |
| height | 每个字符所占的行高 | number | 40 |
| autoStart | 挂载后是否立即播放,同时决定 reset() 之后是否自动重新开始 | boolean | true |
| onFinish | 最后一列落定时触发一次;被下一轮打断则不触发 | () => void | - |
| className | 根容器类名,合并在 classNames.root 之后 | string | - |
| classNames | 各 slot 的类名覆盖,见「样式覆盖」一节 | SlotClassNames<RollingTextSlots> | - |
| ref | 命令式控制的 ref,用于 start / reset | Ref<RollingTextRef> | - |
类型
import type {
RollingTextDirection,
RollingTextNumberProps,
RollingTextProps,
RollingTextRef,
RollingTextSlots,
RollingTextStopOrder,
RollingTextTextProps
} from '@skyroc/native-ui';RollingTextProps 是 RollingTextNumberProps | RollingTextTextProps 的联合,两种模式的互斥字段在类型上标成了 never。
RollingTextDirection
滚动方向。
RollingTextStopOrder
停止顺序,ltr 为左列先停。
RollingTextSlots
可通过 classNames 覆盖的 slot 名称。
SlotClassNames
classNames 的取值形态:把 slot 名映射到类名,每个 slot 都可选。本页用到的 slot 见 RollingTextSlots。
RollingTextRef
组件实例暴露的命令式方法。
| 字段 | 类型 | 说明 |
|---|---|---|
| start* | () => void | 从起始位置播放一次,播放中调用会立即重播。 |
| reset* | () => void | 回到起始位置;autoStart 为 true 时立即重播,否则停在起点。 |