1# Scroll 2 3可滚动的容器组件,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。 4 5> **说明:** 6> - 该组件从API version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 7> - 该组件嵌套List子组件滚动时,若List不设置宽高,则默认全部加载,在对性能有要求的场景下建议指定List的宽高。 8> - 该组件滚动的前提是主轴方向大小小于内容大小。 9> - 该组件回弹的前提是要有滚动。内容小于一屏时,没有回弹效果。 10 11 12## 子组件 13 14支持单个子组件。 15 16 17## 接口 18 19Scroll(scroller?: Scroller) 20 21**参数:** 22 23| 参数名 | 参数类型 | 必填 | 参数描述 | 24| -------- | -------- | -------- | -------- | 25| scroller | [Scroller](#scroller) | 否 | 可滚动组件的控制器。用于与可滚动组件进行绑定。 | 26 27## 属性 28 29除支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性: 30 31| 名称 | 参数类型 | 描述 | 32| -------------- | ---------------------------------------- | --------- | 33| scrollable | [ScrollDirection](#scrolldirection枚举说明) | 设置滚动方向。<br/>默认值:ScrollDirection.Vertical | 34| scrollBar | [BarState](ts-appendix-enums.md#barstate) | 设置滚动条状态。<br/>默认值:BarState.Auto<br/>**说明:** <br/>如果容器组件无法滚动,则滚动条不显示。如果容器组件的子组件大小为无穷大,则滚动条不支持拖动和伴随滚动。 | 35| scrollBarColor | string \| number \| [Color](ts-appendix-enums.md#color) | 设置滚动条的颜色。 | 36| scrollBarWidth | string \| number | 设置滚动条的宽度,不支持百分比设置。<br/>默认值:4<br/>单位:vp<br/>**说明:** <br/>如果滚动条的宽度超过其高度,则滚动条的宽度会变为默认值。 | 37| edgeEffect | [EdgeEffect](ts-appendix-enums.md#edgeeffect) | 设置滑动效果,目前支持的滑动效果参见EdgeEffect的枚举说明。<br/>默认值:EdgeEffect.None | 38 39## ScrollDirection枚举说明 40| 名称 | 描述 | 41| ---------- | ------------------------ | 42| Horizontal | 仅支持水平方向滚动。 | 43| Vertical | 仅支持竖直方向滚动。 | 44| None | 不可滚动。 | 45| Free<sup>(deprecated) </sup> | 支持竖直或水平方向滚动<br/> 从API version 9开始废弃| 46 47## 事件 48 49| 名称 | 功能描述 | 50| ------------------------------------------------------------ | ------------------------------------------------------------ | 51| onScrollFrameBegin<sup>9+</sup>(event: (offset: number, state: ScrollState) => { offsetRemain }) | 每帧开始滚动时触发,事件参数传入即将发生的滚动量,事件处理函数中可根据应用场景计算实际需要的滚动量并作为事件处理函数的返回值返回,Scroll将按照返回值的实际滚动量进行滚动。<br/>\- offset:即将发生的滚动量。<br/>\- state:当前滚动状态。<br/>- offsetRemain:实际滚动量。<br/>触发该事件的条件 :<br/>1、滚动组件触发滚动时触发,包括键鼠操作等其他触发滚动的输入设置。<br/>2、调用控制器接口时不触发。<br/>3、越界回弹不触发。<br/>**说明:** <br/>支持offsetRemain为负值。<br/>若通过onScrollFrameBegine事件和scrollBy方法实现容器嵌套滚动,需设置子滚动节点的EdgeEffect为None。如Scroll嵌套List滚动时,List组件的edgeEffect属性需设置为EdgeEffect.None。 | 52| onScroll(event: (xOffset: number, yOffset: number) => void) | 滚动事件回调, 返回滚动时水平、竖直方向偏移量。<br/>触发该事件的条件 :<br/>1、滚动组件触发滚动时触发,支持键鼠操作等其他触发滚动的输入设置。<br/>2、通过滚动控制器API接口调用。<br/>3、越界回弹。 | 53| onScrollEdge(event: (side: Edge) => void) | 滚动到边缘事件回调。<br/>触发该事件的条件 :<br/>1、滚动组件滚动到边缘时触发,支持键鼠操作等其他触发滚动的输入设置。<br/>2、通过滚动控制器API接口调用。<br/>3、越界回弹。 | 54| onScrollEnd<sup>(deprecated) </sup>(event: () => void) | 滚动停止事件回调。<br>该事件从API version 9开始废弃,使用onScrollStop事件替代。<br/>触发该事件的条件 :<br/>1、滚动组件触发滚动后停止,支持键鼠操作等其他触发滚动的输入设置。<br/>2、通过滚动控制器API接口调用后停止,带过渡动效。 | 55| onScrollStart<sup>9+</sup>(event: () => void) | 滚动开始时触发。手指拖动Scroll或拖动Scroll的滚动条触发的滚动开始时,会触发该事件。使用[Scroller](#scroller)滚动控制器触发的带动画的滚动,动画开始时会触发该事件。<br/>触发该事件的条件 :<br/>1、滚动组件开始滚动时触发,支持键鼠操作等其他触发滚动的输入设置。<br/>2、通过滚动控制器API接口调用后开始,带过渡动效。 | 56| onScrollStop<sup>9+</sup>(event: () => void) | 滚动停止时触发。手拖动Scroll或拖动Scroll的滚动条触发的滚动,手离开屏幕并且滚动停止时会触发该事件。使用[Scroller](#scroller)滚动控制器触发的带动画的滚动,动画停止时会触发该事件。<br/>触发该事件的条件 :<br/>1、滚动组件触发滚动后停止,支持键鼠操作等其他触发滚动的输入设置。<br/>2、通过滚动控制器API接口调用后开始,带过渡动效,。 | 57 58> **说明:** 59> 60> 若通过onScrollFrameBegin事件和scrollBy方法实现容器嵌套滚动,需设置子滚动节点的EdgeEffect为None。如Scroll嵌套List滚动时,List组件的edgeEffect属性需设置为EdgeEffect.None。 61 62## Scroller 63 64可滚动容器组件的控制器,可以将此组件绑定至容器组件,然后通过它控制容器组件的滚动,同一个控制器不可以控制多个容器组件,目前支持绑定到List、Scroll、ScrollBar、Grid、WaterFlow上。 65 66 67### 导入对象 68 69``` 70scroller: Scroller = new Scroller() 71``` 72 73 74### scrollTo 75 76scrollTo(value: { xOffset: number | string, yOffset: number | string, animation?: { duration: number, curve: Curve } }): void 77 78 79滑动到指定位置。 80 81**参数:** 82 83| 参数名 | 参数类型 | 必填 | 参数描述 | 84| --------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 85| xOffset | number \| string | 是 | 水平滑动偏移。<br/>**说明:** <br/>该参数值不支持设置百分比。<br/>仅滚动轴为x轴时生效。 | 86| yOffset | number \| string | 是 | 垂直滑动偏移。<br/>**说明:** <br/>该参数值不支持设置百分比。<br/>仅滚动轴为y轴时生效。 | 87| animation | {<br/>duration: number,<br/>curve: [Curve](ts-appendix-enums.md#curve)<br/>} | 否 | 动画配置:<br/>- duration: 滚动时长设置。<br/>- curve: 滚动曲线设置。<br/>默认值: <br/>{<br/>duration: 0,<br/>curve: Curve.Ease<br/>}<br/>**说明:** <br/>设置为小于0的值时,按默认值显示。 | 88 89 90### scrollEdge 91 92scrollEdge(value: Edge): void 93 94 95滚动到容器边缘,不区分滚动轴方向,Edge.Top和Edge.Start表现相同,Edge.Bottom和Edge.End表现相同。 96 97**参数:** 98 99| 参数名 | 参数类型 | 必填 | 参数描述 | 100| ----- | ---- | ---- | --------- | 101| value | [Edge](ts-appendix-enums.md#edge) | 是 | 滚动到的边缘位置。 | 102 103 104### scrollPage 105 106scrollPage(value: { next: boolean, direction?: Axis }): void 107 108滚动到下一页或者上一页。 109 110**参数:** 111 112| 参数名 | 参数类型 | 必填 | 参数描述 | 113| --------- | ------- | ---- | ------------------------------ | 114| next | boolean | 是 | 是否向下翻页。true表示向下翻页,false表示向上翻页。 | 115| direction<sup>(deprecated) </sup> | [Axis](ts-appendix-enums.md#axis) | 否 | 设置滚动方向为水平或竖直方向。<br/> 从API version 9开始废弃 | 116 117 118### currentOffset 119 120currentOffset(): { xOffset: number, yOffset: number } 121 122 123返回当前的滚动偏移量。 124 125**返回值** 126 127| 类型 | 描述 | 128| ---------------------------------------------------------- | ------------------------------------------------------------ | 129| {<br/>xOffset: number,<br/>yOffset: number<br/>} | xOffset: 水平滑动偏移;<br/>yOffset: 竖直滑动偏移。<br/>**说明:** <br/>返回值单位为vp。 | 130 131 132### scrollToIndex 133 134scrollToIndex(value: number): void 135 136 137滑动到指定Index。 138 139 140> **说明:** 141> 142> 仅支持Grid、List、WaterFlow组件。 143 144**参数:** 145 146| 参数名 | 参数类型 | 必填 | 参数描述 | 147| ------ | -------- | ---- | ---------------------------------- | 148| value | number | 是 | 要滑动到的列表项在列表中的索引值。 | 149 150 151### scrollBy<sup>9+</sup> 152 153scrollBy(dx: Length, dy: Length): void 154 155 156滑动指定距离。 157 158 159> **说明:** 160> 161> 仅支持Scroll、ScrollBar、Grid、List组件。 162 163**参数:** 164 165| 参数名 | 参数类型 | 必填 | 参数描述 | 166| ----- | ------ | ---- | ----------------- | 167| dx | Length | 是 | 水平方向滚动距离,不支持百分比形式。 | 168| dy | Length | 是 | 竖直方向滚动距离,不支持百分比形式。 | 169 170 171## 示例 172### 示例1 173 174```ts 175// xxx.ets 176@Entry 177@Component 178struct ScrollExample { 179 scroller: Scroller = new Scroller() 180 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 181 182 build() { 183 Stack({ alignContent: Alignment.TopStart }) { 184 Scroll(this.scroller) { 185 Column() { 186 ForEach(this.arr, (item) => { 187 Text(item.toString()) 188 .width('90%') 189 .height(150) 190 .backgroundColor(0xFFFFFF) 191 .borderRadius(15) 192 .fontSize(16) 193 .textAlign(TextAlign.Center) 194 .margin({ top: 10 }) 195 }, item => item) 196 }.width('100%') 197 } 198 .scrollable(ScrollDirection.Vertical) // 滚动方向纵向 199 .scrollBar(BarState.On) // 滚动条常驻显示 200 .scrollBarColor(Color.Gray) // 滚动条颜色 201 .scrollBarWidth(10) // 滚动条宽度 202 .edgeEffect(EdgeEffect.None) 203 .onScroll((xOffset: number, yOffset: number) => { 204 console.info(xOffset + ' ' + yOffset) 205 }) 206 .onScrollEdge((side: Edge) => { 207 console.info('To the edge') 208 }) 209 .onScrollEnd(() => { 210 console.info('Scroll Stop') 211 }) 212 213 Button('scroll 150') 214 .height('5%') 215 .onClick(() => { // 点击后下滑指定距离150.0vp 216 this.scroller.scrollBy(0,150) 217 }) 218 .margin({ top: 10, left: 20 }) 219 Button('scroll 100') 220 .height('5%') 221 .onClick(() => { // 点击后滑动到指定位置,即下滑100.0vp的距离 222 this.scroller.scrollTo({ xOffset: 0, yOffset: this.scroller.currentOffset().yOffset + 100 }) 223 }) 224 .margin({ top: 60, left: 20 }) 225 Button('back top') 226 .height('5%') 227 .onClick(() => { // 点击后回到顶部 228 this.scroller.scrollEdge(Edge.Top) 229 }) 230 .margin({ top: 110, left: 20 }) 231 Button('next page') 232 .height('5%') 233 .onClick(() => { // 点击后滑到下一页 234 this.scroller.scrollPage({ next: true }) 235 }) 236 .margin({ top: 170, left: 20 }) 237 }.width('100%').height('100%').backgroundColor(0xDCDCDC) 238 } 239} 240``` 241 242![zh-cn_image_0000001174104386](figures/zh-cn_image_0000001174104386.gif) 243 244### 示例2 245```ts 246@Entry 247@Component 248struct NestedScroll { 249 @State listPosition: number = 0; // 0代表滚动到List顶部,1代表中间值,2代表滚动到List底部。 250 private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 251 private scrollerForScroll: Scroller = new Scroller() 252 private scrollerForList: Scroller = new Scroller() 253 254 build() { 255 Flex() { 256 Scroll(this.scrollerForScroll) { 257 Column() { 258 Text("Scroll Area") 259 .width("100%").height("40%").backgroundColor(0X330000FF) 260 .fontSize(16).textAlign(TextAlign.Center) 261 .onClick(() => { 262 this.scrollerForList.scrollToIndex(5) 263 }) 264 265 List({ space: 20, scroller: this.scrollerForList }) { 266 ForEach(this.arr, (item) => { 267 ListItem() { 268 Text("ListItem" + item) 269 .width("100%").height("100%").borderRadius(15) 270 .fontSize(16).textAlign(TextAlign.Center).backgroundColor(Color.White) 271 }.width("100%").height(100) 272 }, item => item) 273 } 274 .width("100%") 275 .height("50%") 276 .edgeEffect(EdgeEffect.None) 277 .onReachStart(() => { 278 this.listPosition = 0 279 }) 280 .onReachEnd(() => { 281 this.listPosition = 2 282 }) 283 .onScrollFrameBegin((offset: number) => { 284 if ((this.listPosition == 0 && offset <= 0) || (this.listPosition == 2 && offset >= 0)) { 285 this.scrollerForScroll.scrollBy(0, offset) 286 return { offsetRemain: 0 } 287 } 288 this.listPosition = 1 289 return { offsetRemain: offset }; 290 }) 291 292 Text("Scroll Area") 293 .width("100%").height("40%").backgroundColor(0X330000FF) 294 .fontSize(16).textAlign(TextAlign.Center) 295 } 296 } 297 .width("100%").height("100%") 298 }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20) 299 } 300} 301``` 302 303![NestedScroll](figures/NestedScroll.gif)