ScrollViewReader
ScrollViewReader 组件,用于在脚本中获得对可滚动内容的编程化控制能力,使开发者能够在运行时滚动至任意视图位置,包括列表项、文本节点等。
ScrollViewReader 与 SwiftUI 的行为保持一致:
开发者通过一个回调函数获得一个 ScrollViewProxy 实例,并可以在任意时机调用 scrollTo(id) 控制滚动视图的位置。
ScrollViewProxy
ScrollViewProxy 是提供滚动控制的代理对象,由 ScrollViewReader 在渲染期间自动注入。
1interface ScrollViewProxy {
2 scrollTo: (id: string | number, anchor?: KeywordPoint | Point) => void;
3}
方法
scrollTo(id, anchor?)
滚动到某个具有指定 id 的元素。
该 id 必须在可滚动内容内存在,并通过 key 配置。
参数说明
| 参数 |
类型 |
必须 |
说明 |
| id |
string |
number |
是 |
| anchor |
KeywordPoint |
Point |
否 |
KeywordPoint 类型
属于字符串关键字,常用:
Point 类型
用于精确控制滚动位置:
1type Point = {
2 x: number
3 y: number
4}
ScrollViewReader
ScrollViewReader 用于包裹可滚动内容,并提供一个 scrollViewProxy 以控制内部滚动。
1type ScrollViewReaderProps = {
2 children: (scrollViewProxy: ScrollViewProxy) => VirtualNode
3};
4declare const ScrollViewReader: FunctionComponent<ScrollViewReaderProps>
Props 说明
| 名称 |
类型 |
必须 |
说明 |
| children |
(proxy: ScrollViewProxy) => VirtualNode |
是 |
回调函数,将滚动代理传给开发者,并返回 ScrollView、List 等可滚动视图。 |
使用说明
- ScrollViewReader 必须包裹 List、ScrollView 等可滚动组件。
- 回调中的 proxy 只在视图构建阶段提供一次,开发者可利用
useRef 保存。
- 支持在动画中使用,例如
withAnimation。
- 锚点可选,不传则使用默认对齐方式。
- 所有 ScrollView 内部节点都可以使用
key 来作为 scrollTo 的目标。
基础示例
下面是一个完整的使用示例,包括滚动到指定元素以及使用动画的方式。
1import {
2 Button,
3 Navigation,
4 NavigationStack,
5 Script,
6 Text,
7 List,
8 ScrollViewReader,
9 ScrollView,
10 VStack,
11 useRef,
12 ScrollViewProxy,
13 withAnimation
14} from "scripting"
15
16function Item({ index }: { index: number }) {
17 return <Text>
18 Item - {index}
19 </Text>
20}
21
22function View() {
23 const dismiss = Navigation.useDismiss()
24 const proxyRef = useRef<ScrollViewProxy>()
25
26 return <NavigationStack>
27 <VStack navigationTitle="ScrollViewReader">
28
29 <ScrollViewReader>
30 {(proxy) => {
31 // 记录 proxy 实例,供按钮点击时使用
32 proxyRef.current = proxy
33
34 return <List>
35 {new Array(100).fill(0).map((_, index) =>
36 <Item
37 key={index}
38 index={index}
39 />
40 )}
41 <Text key="bottom">
42 Bottom
43 </Text>
44 </List>
45 }}
46 </ScrollViewReader>
47
48 <Button
49 title="跳转"
50 action={() => {
51 if (proxyRef.current == null) {
52 console.log("no proxy found")
53 return
54 }
55
56 const index = Math.random() * 100 | 0
57
58 withAnimation(() => {
59 proxyRef.current?.scrollTo(index, "bottom")
60 // proxyRef.current?.scrollTo("bottom", "bottom")
61 })
62 }}
63 />
64
65 </VStack>
66 </NavigationStack>
67}
68
69async function run() {
70 await Navigation.present(<View />)
71 Script.exit()
72}
73
74run()
关于 ID(key)匹配的说明
scrollTo(id) 依赖于内部节点的 key 属性。
以下配置都可作为滚动目标:
1<Text key="bottom">Bottom</Text>
key 与 SwiftUI 的 .id() 行为保持一致。
动画支持
ScrollViewReader 支持结合 withAnimation 来进行平滑滚动。例如:
1withAnimation(() => {
2 proxy.scrollTo("target", "center")
3})
在动画块中触发滚动,将获得平滑过渡。
注意事项
- 必须在 ScrollViewReader 回调中记录 proxy,否则外部无法访问。
- 必须确保目标元素存在并有唯一 id,否则无法滚到目标位置。
- 不支持在 ScrollViewReader 外部渲染可滚动组件。
- 滚动行为与 SwiftUI 基本一致,包括 anchor 对齐方式。