BackTop
滚动一段距离后出现的回到顶部按钮
回到顶部(BackTop)在页面滚过一定距离后浮现在右下角,点击把目标容器滚回顶部。组件基于 FloatingButton 封装,显隐判定与滚动指令全程留在 UI 线程:滚动的每一帧都要判断按钮是否该出现,走 React state 会把整棵子树重渲染一遍。
import { BackTop } from '@skyroc/native-ui';基础用法
把滚动容器换成 Animated.ScrollView(或 Animated.FlatList),用 useAnimatedRef 拿到 ref 传给 target 即可。往下滚超过 200px 按钮出现,点击滚回顶部。
import { BackTop, Cell, Portal, Text } from '@skyroc/native-ui';
import { useState } from 'react';
import { View } from 'react-native';
import Animated, { useAnimatedRef } from 'react-native-reanimated';
/** 用来把页面撑到能滚动的假数据 */
const ROWS = Array.from({ length: 40 }, (_, index) => index + 1);
const BackTopBasic = () => {
const [pressCount, setPressCount] = useState(0);
const scrollRef = useAnimatedRef<Animated.ScrollView>();
function handlePress() {
setPressCount(prev => prev + 1);
}
return (
<View className="flex-1 bg-muted">
<Animated.ScrollView
ref={scrollRef}
className="flex-1"
contentContainerClassName="pb-24"
showsVerticalScrollIndicator={false}
>
<Text className="mb-2 mt-4 px-4 text-lg font-semibold">基础用法</Text>
<Text className="mb-4 px-4 text-sm text-muted-foreground">
往下滚超过 200px,右下角出现按钮;点一下回到顶部。显隐判断全程在 UI 线程,滚动时不会触发重渲染。
</Text>
<Text className="mb-4 px-4 text-sm text-muted-foreground">已点击 {pressCount} 次</Text>
{ROWS.map(row => (
<Cell
key={row}
title={`第 ${row} 行`}
trailing={String(row)}
/>
))}
</Animated.ScrollView>
{/* 套 Portal 是因为 bottom / right 是相对屏幕边缘算的,而本页顶部还有一个 NavBar */}
<Portal>
<BackTop
target={scrollRef}
onPress={handlePress}
/>
</Portal>
</View>
);
};
export { BackTopBasic };何时使用
- 长列表、长文详情页等一屏放不下、用户需要往回翻的场景。
- 内容不足两屏时不必加:默认阈值是 200px,短页面刚滚一下按钮就弹出来反而是干扰。
- 需要的是一个常驻的主操作入口(发布、客服)时用
FloatingButton,它可拖拽、可吸附边缘;BackTop是固定位置的次要动作。
目标容器
target 接收 useAnimatedRef 返回的 AnimatedRef,读滚动距离和执行 scrollTo 都靠它。Animated.ScrollView 与 Animated.FlatList 一视同仁,列表不必为了回顶退回 ScrollView;其它滚动组件经 Animated.createAnimatedComponent 包装后同样适用。
const scrollRef = useAnimatedRef<Animated.FlatList<Item>>();
<Animated.FlatList ref={scrollRef} data={data} renderItem={renderItem} />
<BackTop target={scrollRef} />target 是必填的,且必须是 Reanimated 的 AnimatedRef——普通 useRef 拿不到 UI 线程可读的滚动偏移。
位置
right / bottom 是按钮到父容器边缘的距离,size 是按钮直径:
| 属性 | 默认值 | 说明 |
|---|---|---|
right | 30 | 距父容器右边的距离 |
bottom | 128 | 距父容器底边的距离,已预留 TabBar |
size | 40 | 按钮直径,比 FloatingButton 的默认 48 小一号 |
位置是相对父容器的绝对定位,边界取父容器的实测尺寸——挂在整屏容器里就贴屏幕边缘。页面上方还有 NavBar 之类的固定元素时,用 Portal 把它挂到页面根节点,避免按钮被这些元素挤下去(示例里就是这么做的)。
bottom 不含安全区:位置最终落在 transform 上,取不到 *-safe 工具类背后的运行时 inset。需要避开 home indicator 或常驻 TabBar 时,把相应高度自己并进这个值。
显示阈值
offset 是按钮出现所需的滚动距离(像素),默认 200——大约滚过一屏。注意它和 FloatingButton 表示坐标的 offset 不是一回事。
<BackTop offset={400} target={scrollRef} />阈值判定是 scrollOffset >= offset,结果保存在一个 Reanimated 共享值里,直接交给 FloatingButton 的 visible,滚动过程中不触发任何 JS 端渲染。显隐动画是 180ms 的缩放缓动。
滚动行为
immediate 为 false(默认)时走滚动动画,为 true 时瞬间跳到顶部。超长列表上瞬间跳顶更利落,也省掉动画期间的连续布局。
<BackTop immediate target={scrollRef} />onPress 在滚动开始前触发,可用于埋点;它不代表滚动已经结束。
自定义内容
不传 children 时渲染默认的向上箭头(Octicons 的 chevron-up,20px,颜色跟随 accent-primary-foreground)。传 children 可整体替换,比如换成文字或自定义图标。
<BackTop target={scrollRef}>
<Text className="text-xs text-primary-foreground">顶部</Text>
</BackTop>按钮底色由 FloatingButton 的 bg-primary 提供,改底色用 className;自定义图标的颜色要自己指定,@expo/vector-icons 不认 className。
禁用
disabled 后按钮不响应点击并整体降低不透明度,但显隐仍然跟随滚动——按钮还在,只是点不动。
API
BackTop
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| target* | 目标滚动容器的 AnimatedRef,用于读取滚动距离与执行 scrollTo | AnimatedRef<BackTopScrollable> | - |
| offset | 显示阈值(像素),滚动距离超过该值按钮才出现 | number | 200 |
| right | 距父容器右边的距离(像素) | number | 30 |
| bottom | 距父容器底边的距离(像素),不含安全区,需要避开 home indicator 或 TabBar 时自行并入 | number | 128 |
| size | 按钮直径(像素) | number | 40 |
| immediate | 为 true 时瞬间跳到顶部,为 false 时走滚动动画 | boolean | false |
| children | 自定义内容,替换默认的向上箭头 | ReactNode | - |
| disabled | 禁用后不响应点击并整体降低不透明度,显隐仍然跟随滚动 | boolean | false |
| onPress | 点击回调,在滚动开始前触发 | () => void | - |
| className | Uniwind 类名,透传给 FloatingButton 的根节点 | string | - |
| style | 根节点自定义样式,叠在动画样式之上 | StyleProp<ViewStyle> | - |
类型
import type { BackTopProps, BackTopScrollable } from '@skyroc/native-ui';BackTopProps 带一个泛型参数 TRef extends BackTopScrollable,默认 Animated.ScrollView,用于约束 target 的类型。
BackTopScrollable
可回顶的滚动容器;其它滚动组件经 createAnimatedComponent 包装后同样适用,这里只列出 Reanimated 内置的两个。