1# Scroll 2 3The **\<Scroll>** component scrolls the content when the layout size of a component exceeds the size of its parent component. 4 5> **NOTE** 6> - This component is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version. 7> - When nesting a **\<List>** within this component, specify the width and height for the **\<List>** under scenarios where consistently high performance is required. If the width and height are not specified, this component will load all content of the **\<List>**. 8> - This component can scroll only when the size on the main axis is less than the content size. 9> - This component can produce a bounce effect only when there is more than one screen of content. 10 11 12## Child Components 13 14This component supports only one child component. 15 16 17## APIs 18 19Scroll(scroller?: Scroller) 20 21**Parameters** 22 23| Name| Type| Mandatory| Description| 24| -------- | -------- | -------- | -------- | 25| scroller | [Scroller](#scroller) | No| Scroller, which can be bound to scrollable components.| 26 27## Attributes 28 29In addition to the [universal attributes](ts-universal-attributes-size.md), the following attributes are supported. 30 31| Name | Type | Description | 32| -------------- | ---------------------------------------- | --------- | 33| scrollable | [ScrollDirection](#scrolldirection) | Scroll direction.<br>Default value: **ScrollDirection.Vertical**| 34| scrollBar | [BarState](ts-appendix-enums.md#barstate) | Scrollbar status.<br>Default value: **BarState.Auto**<br>**NOTE**<br>If the container component cannot be scrolled, the scrollbar is not displayed. If the size of a child component of a container component is infinite, the scrollbar cannot be dragged or scrolled with the child component.| 35| scrollBarColor | string \| number \| [Color](ts-appendix-enums.md#color) | Color of the scrollbar.| 36| scrollBarWidth | string \| number | Width of the scrollbar. This attribute cannot be set in percentage.<br>Default value: **4**<br>Unit: vp<br>**NOTE**<br>If the width of the scrollbar exceeds its height, it will change to the default value.| 37| scrollSnap<sup>10+</sup> | [ScrollSnapOptions](#scrollsnapoptions10) | Scroll snapping mode.| 38| edgeEffect | value:[EdgeEffect](ts-appendix-enums.md#edgeeffect),<br>options?:[EdgeEffectOptions<sup>11+</sup>](#edgeeffectoptions11) | Effect used at the edges of the component when the boundary of the scrollable content is reached.<br>\- **value**: effect used at the edges of the **\<Scroll>** component when the boundary of the scrollable content is reached. The spring effect and shadow effect are supported.<br>Default value: **EdgeEffect.None**<br>\- **options**: whether to enable the scroll effect when the component content size is smaller than the component itself.<br>Default value: **true**| 39| enableScrollInteraction<sup>10+</sup> | boolean | Whether to support scroll gestures. When this attribute is set to **false**, scrolling by finger or mouse is not supported, but the scrolling controller API is not affected.<br>Default value: **true** | 40| nestedScroll<sup>10+</sup> | [NestedScrollOptions](#nestedscrolloptions10) | Nested scrolling options. You can set the nested scrolling mode in the forward and backward directions to implement scrolling linkage with the parent component.| 41| friction<sup>10+</sup> | number \| [Resource](ts-types.md#resource) | Friction coefficient. It applies only to gestures in the scrolling area, and it affects only indirectly the scroll chaining during the inertial scrolling process.<br>Default value: **0.9** for wearable devices and **0.6** for non-wearable devices<br>**NOTE**<br>A value less than or equal to 0 evaluates to the default value.| 42| enablePaging<sup>11+</sup> | boolean | Whether to enable the swipe-to-turn-pages feature.<br>Default value: **false**<br>**NOTE**<br>If both **enablePaging** and **scrollSnap** are set, **scrollSnap** takes effect, but **enablePaging** does not.| 43 44## ScrollDirection 45| Name | Description | 46| ---------- | ------------------------ | 47| Horizontal | Only horizontal scrolling is supported. | 48| Vertical | Only vertical scrolling is supported. | 49| None | Scrolling is disabled. | 50| Free<sup>(deprecated) </sup> | Vertical or horizontal scrolling is supported.<br> This API is deprecated since API version 9.| 51 52## ScrollSnapOptions<sup>10+</sup> 53| Name | Type | Mandatory | Description | 54| ---------- | --------------------|-------------------- | -------- | 55| snapAlign | [ScrollSnapAlign](ts-container-list.md#scrollsnapalign10) | Yes| Alignment mode for the scroll snap position.<br>**NOTE**<br>1. Default value: **ScrollSnapAlign.NONE**<br>2. This API takes effect only when **snapPagination** is set to **Dimension**. **Array\<Dimension\>** is not supported.| 56| snapPagination | [Dimension](ts-types.md#dimension10) \| Array\<Dimension\> | No| Snap points for the **\<Scroll>** component. Each snap point defines the offset from an edge to which the **\<Scroll>** component can scroll.<br>**NOTE**<br>1. A value of the **Dimension** type indicates the size per page. The system automatically works out the position of each snap point based on the value. For example, if the value is **500**, the position of the snap point is [0,500,1000,1500, ...].<br>2. A value of the **Array\<Dimension\>** type indicates an array of snap point positions defined by **Dimension**. The range of each dimension is [0, scrollable distance]. Point 0 and the bottom of the scrollable distance automatically become the snap points.<br>3. If this attribute is not set or **Dimension** is set to a value less than or equal to 0, the value is regarded as an abnormal value. In this case, there is no scroll snapping. When the value is of the **Array\<Dimension\>** type, the items in the array must be monotonically increasing.<br>4. When the value is a percentage, the actual size is the product of the viewport of the **\<Scroll>** component and the percentage value.| 57| enableSnapToStart | boolean | No| Whether to enable the snap to start feature. When scroll snapping is defined for the **\<Scroll>** component, setting this attribute to **false** enables the component to scroll between the start edge and the first snap point.<br>**NOTE**<br>1. Default value: **true**<br>2. This attribute takes effect only when **snapPagination** is set to a value of the **Array\<Dimension\>** type; it does not work with values of the **Dimension** type.| 58| enableSnapToEnd | boolean | No| Whether to enable the snap to end feature. When scroll snapping is defined for the **\<Scroll>** component, setting this attribute to **false** enables the component to scroll between the end edge and the last snap point.<br>**NOTE**<br>1. Default value: **true**<br>2. This attribute takes effect only when **snapPagination** is set to a value of the **Array\<Dimension\>** type; it does not work with values of the **Dimension** type.| 59 60## Events 61 62| Name | Description | 63| ------------------------------------------------------------ | ------------------------------------------------------------ | 64| onScrollFrameBegin<sup>9+</sup>(event: (offset: number, state: [ScrollState](ts-container-list.md#scrollstate)) => { offsetRemain: number; }) | Triggered when each frame scrolling starts. The input parameters indicate the amount by which the **\<Scroll>** component will scroll. The event handler then works out the amount by which the component needs to scroll based on the real-world situation and returns the result.<br>\- **offset**: amount to scroll by.<br>\- **state**: current scrolling status.<br>- **offsetRemain**: actual amount by which the component scrolls.<br>**NOTE**<br>1. This event is triggered when scrolling is started by the **\<Scroll>** component or other input settings, such as keyboard and mouse operations.<br>2. This event is not triggered when the controller API is called.<br>3. This event does not support the out-of-bounds bounce effect.<br>4. This event is not triggered when the scroll bar is dragged.<br>**NOTE**<br>The value of **offsetRemain** can be a negative value.<br>If the **onScrollFrameBegin** event and **scrollBy** method are used to implement nested scrolling, set the **edgeEffect** attribute of the scrollable child component to **None**. For example, if a **\<List>** is nested in the **\<Scroll>** component, **edgeEffect** of the **\<List>** must be set to **EdgeEffect.None**.| 65| onScroll(event: (xOffset: number, yOffset: number) => void) | Triggered to return the horizontal and vertical offsets during scrolling when the specified scroll event occurs.<br>**NOTE**<br>1. This event is triggered when scrolling is started by the **\<Scroll>** component or other input settings, such as keyboard and mouse operations.<br>2. This event is triggered when the controller API is called.<br>3. This event supports the out-of-bounds bounce effect.| 66| onScrollEdge(event: (side: Edge) => void) | Triggered when scrolling reaches the edge.<br>**NOTE**<br>1. This event is triggered when scrolling reaches the edge after being started by the **\<Scroll>** component or other input settings, such as keyboard and mouse operations.<br>2. This event is triggered when the controller API is called.<br>3. This event supports the out-of-bounds bounce effect.| 67| onScrollEnd<sup>(deprecated) </sup>(event: () => void) | Triggered when scrolling stops.<br>This event is deprecated since API version 9. Use the **onScrollStop** event instead.<br>**NOTE**<br>1. This event is triggered when scrolling is stopped by the **\<Scroll>** component or other input settings, such as keyboard and mouse operations.<br>2. This event is triggered when the controller API is called, accompanied by a transition animation.| 68| onScrollStart<sup>9+</sup>(event: () => void) | Triggered when scrolling starts and is initiated by the user's finger dragging the **\<Scroll>** component or its scrollbar. This event is also triggered when the animation contained in the scrolling triggered by [Scroller](#scroller) starts.<br>**NOTE**<br>1. This event is triggered when scrolling is started by the **\<Scroll>** component or other input settings, such as keyboard and mouse operations.<br>2. This event is triggered when the controller API is called, accompanied by a transition animation.| 69| onScrollStop<sup>9+</sup>(event: () => void) | Triggered when scrolling stops after the user's finger leaves the screen. This event is also triggered when the animation contained in the scrolling triggered by [Scroller](#scroller) stops.<br>**NOTE**<br>1. This event is triggered when scrolling is stopped by the **\<Scroll>** component or other input settings, such as keyboard and mouse operations.<br>2. This event is triggered when the controller API is called, accompanied by a transition animation.| 70| onReachStart<sup>11+</sup>(event: () => void) | Triggered when the **\<Scroll>** component reaches the start position.<br>**NOTE**<br>This event is triggered once when the component is initialized and once when the component scrolls to the start position. When the component's edge effect is the spring effect, this event is triggered once when the component passes the start position and is triggered again when the component returns to the start position.| 71| onReachEnd<sup>11+</sup>(event: () => void) | Triggered when the **\<Scroll>** component reaches the end position.<br>**NOTE**<br>When the component's edge effect is the spring effect, this event is triggered once when the component passes the end position and is triggered again when the component returns to the end position.| 72 73> **NOTE** 74> 75> If the **onScrollFrameBegin** event and **scrollBy** method are used to implement nested scrolling, set the **edgeEffect** attribute of the scrollable child component to **None**. For example, if a **\<List>** is nested in the **\<Scroll>** component, **edgeEffect** of the **\<List>** must be set to **EdgeEffect.None**. 76 77## Scroller 78 79Implements a controller for a scrollable container component. You can bind this component to a container component and use it to control the scrolling of that component. One controller can control only one container component. The supported container components are **\<List>**, **\<Scroll>**, **\<ScrollBar>**, **\<Grid>**, and **\<WaterFlow>**. 80 81 82### Objects to Import 83 84``` 85scroller: Scroller = new Scroller() 86``` 87 88 89### scrollTo 90 91scrollTo(value: { xOffset: number | string, yOffset: number | string, animation?: { duration?: number, curve?: Curve | ICurve } | boolean }): void 92 93 94Scrolls to the specified position. 95 96**Parameters** 97 98| Name | Type | Mandatory| Description | 99| --------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 100| xOffset | number \| string | Yes | Horizontal scrolling offset.<br>**NOTE**<br>This parameter cannot be set in percentage.<br>If the value is less than 0, the offset will be 0 for scrolling without animation; scrolling with animation stops when it reaches the start position.<br>This parameter takes effect only when the scroll axis is the x-axis.| 101| yOffset | number \| string | Yes | Vertical scrolling offset.<br>**NOTE**<br>This parameter cannot be set in percentage.<br>If the value is less than 0, the offset will be 0 for scrolling without animation; scrolling with animation stops when it reaches the start position.<br>This parameter takes effect only when the scroll axis is the y-axis.| 102| animation | {duration?: number, curve?: [Curve](ts-appendix-enums.md#curve) \| [ICurve](../apis/js-apis-curve.md#icurve)<sup>10+ </sup>} \| boolean<sup>10+ </sup> | No | Animation configuration, which includes the following:<br>- **duration**: scrolling duration.<br>- **curve**: scrolling curve.<br>- **boolean**: whether to enable the default spring animation.<br>Default value:<br>{<br>duration: 1000,<br>curve: Curve.Ease<br>}<br>boolean: false<br>**NOTE**<br>A value less than 0 evaluates to the default value.<br>Currently, the **\<List>**, **\<Scroll>**, **\<Grid>**, and **\<WaterFlow>** support the **Boolean** type and **ICurve**.| 103 104 105### scrollEdge 106 107scrollEdge(value: Edge): void 108 109 110Scrolls to the edge of the container, regardless of the scroll axis direction. **Edge.Top** and **Edge.Start** produce the same effect, and **Edge.Bottom** and **Edge.End** produce the same effect. 111 112**Parameters** 113 114| Name | Type| Mandatory | Description | 115| ----- | ---- | ---- | --------- | 116| value | [Edge](ts-appendix-enums.md#edge) | Yes | Edge position to scroll to.| 117 118### scrollPage<sup>9+</sup> 119 120scrollPage(value: { next: boolean }): void 121 122Scrolls to the next or previous page. 123 124**Parameters** 125 126| Name | Type | Mandatory| Description | 127| --------------------------------- | --------------------------------- | ---- | ----------------------------------------------------------- | 128| next | boolean | Yes | Whether to turn to the next page. The value **true** means to scroll to the next page, and **false** means to scroll to the previous page. | 129 130### scrollPage<sup>(deprecated)</sup> 131 132scrollPage(value: { next: boolean, direction?: Axis }): void 133 134Scrolls to the next or previous page. This API is deprecated since API version 9. You are advised to use [scrollPage<sup>9+</sup>](#scrollpage9) instead. 135 136**Parameters** 137 138| Name | Type | Mandatory | Description | 139| --------- | ------- | ---- | ------------------------------ | 140| next | boolean | Yes | Whether to turn to the next page. The value **true** means to scroll to the next page, and **false** means to scroll to the previous page.| 141| direction | [Axis](ts-appendix-enums.md#axis) | No | Scrolling direction: horizontal or vertical. | 142 143### currentOffset 144 145currentOffset(): OffsetResult 146 147| Type | Description| 148| -------- | -------- | 149| [OffsetResult<sup>11+</sup>](#offsetresult11) | Obtains the scrolling offset.<br>**NOTE**<br>If **Scroller** is not bound to a container component or the container component is released abnormally, the return value for **currentOffset** is null.| 150 151### scrollToIndex 152 153scrollToIndex(value: number, smooth?: boolean, align?: ScrollAlign): void 154 155Scrolls to the item with the specified index. 156 157When **smooth** is set to **true**, all passed items are loaded and counted in layout calculation. This may result in performance issues if a large number of items are involved. 158 159 160> **NOTE** 161> 162> This API only works for the **\<Grid>**, **\<List>**, and **\<WaterFlow>** components. 163 164**Parameters** 165 166| Name | Type| Mandatory| Description | 167| --------------------- | -------- | ---- | ------------------------------------------------------------ | 168| value | number | Yes | Index of the item to be scrolled to in the container.<br>**NOTE**<br>If the value set is a negative value or greater than the maximum index of the items in the container, the value is deemed abnormal, and no scrolling will be performed. | 169| smooth | boolean | No | Whether to enable the smooth animation for scrolling to the item with the specified index. The value **true** means to enable that the smooth animation, and **false** means the opposite.<br>Default value: **false**| 170| align | [ScrollAlign](#scrollalign10) | No | How the list item to scroll to is aligned with the container.<br>Default value when the container is **\<List>**: **ScrollAlign.START**<br> Default value when the container is **\<Grid>**: **ScrollAlign.AUTO**<br> Default value when the container is **\<WaterFlow>**: **ScrollAlign.START**<br>**NOTE**<br>This parameter is only available for the **\<List>**, **\<Grid>**, and **\<WaterFlow>** components.| 171 172### scrollBy<sup>9+</sup> 173 174scrollBy(dx: Length, dy: Length): void 175 176 177Scrolls by the specified amount. 178 179 180> **NOTE** 181> 182> This API is available for the **\<Scroll>**, **\<List>**, **\<Grid>**, and **\<WaterFlow>** components. 183 184**Parameters** 185 186| Name | Type | Mandatory | Description | 187| ----- | ------ | ---- | ----------------- | 188| dx | [Length](ts-types.md#length) | Yes | Amount to scroll by in the horizontal direction. The percentage format is not supported.| 189| dy | [Length](ts-types.md#length) | Yes | Amount to scroll by in the vertical direction. The percentage format is not supported.| 190 191### isAtEnd<sup>10+</sup> 192 193isAtEnd(): boolean 194 195Checks whether the component has scrolled to the bottom. 196 197> **NOTE** 198> 199> This API is available for the **\<Scroll>**, **\<List>**, **\<Grid>**, and **\<WaterFlow>** components. 200 201**Return value** 202 203| Type | Description | 204| ------- | -------- | 205| boolean | The value **true** means that the component has scrolled to the bottom, and **false** means the opposite.| 206 207### getItemRect<sup>11+</sup> 208 209getItemRect(index: number): RectResult 210 211Obtains the size and position of a child component. 212 213> **NOTE** 214> 215> This API is available for the **\<Scroll>**, **\<List>**, **\<Grid>**, and **\<WaterFlow>** components. 216 217**Parameters** 218 219| Name | Type | Mandatory | Description | 220| ----- | ------ | ---- | ----------------- | 221| index | number | Yes | Index of the target child component.| 222 223> **NOTE** 224> 225> - The value of **index** must be the index of a child component visible in the display area. Otherwise, the value is considered invalid. 226> - The size and position returned for an invalid value are both **0**. 227 228**Return value** 229 230| Type | Description | 231| ------------------- | -------- | 232| [RectResult](ts-types.md#rectresult10) | Size and position of the child component relative to the component.<br>Unit: vp| 233 234## OffsetResult<sup>11+</sup> 235 236| Name| Type | Description | 237| --------------|-------------------------------------------- | ------------------------------------------------------------ | 238| xOffset | number | Horizontal scrolling offset.<br>The unit of the return value is vp.| 239| yOffset | number | Vertical scrolling offset.<br>The unit of the return value is vp.| 240 241## ScrollAlign<sup>10+</sup> 242 243| Name | Description | 244| ------ | ------------------------------ | 245| START | The start edge of the list item is flush with the start edge of the list. | 246| CENTER | The list item is centered along the main axis of the list. | 247| END | The end edge of the list item is flush with the end edge of the list.| 248| AUTO | The list item is automatically aligned.<br>If the list item is fully contained within the display area, no adjustment is performed. Otherwise, the list item is aligned so that its start or end edge is flush with the start or end edge of the list, whichever requires a shorter scrolling distance.| 249 250## NestedScrollOptions<sup>10+ </sup> 251| Name | Type | Mandatory| Description | 252| ----- | ------ | ------ | ----------------- | 253| scrollForward | NestedScrollMode | Yes| Nested scrolling option when the component scrolls forward.| 254| scrollBackward | NestedScrollMode | Yes| Nested scrolling option when the component scrolls backward.| 255 256## NestedScrollMode<sup>10+ </sup> 257| Name | Description | 258| ------ | ------------------------------ | 259| SELF_ONLY | The scrolling is contained within the component, and no scroll chaining occurs, that is, the parent component does not scroll when the component scrolling reaches the boundary. | 260| SELF_FIRST | The component scrolls first, and when it hits the boundary, the parent component scrolls. When the parent component hits the boundary, its edge effect is displayed. If no edge effect is specified for the parent component, the edge effect of the child component is displayed instead. | 261| PARENT_FIRST | The parent component scrolls first, and when it hits the boundary, the component scrolls. When the component hits the boundary, its edge effect is displayed. If no edge effect is specified for the component, the edge effect of the parent component is displayed instead.| 262| PARALLEL | The component and its parent component scroll at the same time. When both the component and its parent component hit the boundary, the edge effect of the component is displayed. If no edge effect is specified for the component, the edge effect of the parent component is displayed instead.| 263 264## EdgeEffectOptions<sup>11+ </sup> 265| Name | Type | Mandatory| Description | 266| ----- | ------| ------- | ----------------- | 267| alwaysEnabled | boolean | Yes| Whether to enable the scroll effect when the component content is smaller than the component itself.| 268 269 270## Example 271### Example 1 272 273```ts 274// xxx.ets 275import Curves from '@ohos.curves' 276 277@Entry 278@Component 279struct ScrollExample { 280 scroller: Scroller = new Scroller() 281 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 282 283 build() { 284 Stack({ alignContent: Alignment.TopStart }) { 285 Scroll(this.scroller) { 286 Column() { 287 ForEach(this.arr, (item: number) => { 288 Text(item.toString()) 289 .width('90%') 290 .height(150) 291 .backgroundColor(0xFFFFFF) 292 .borderRadius(15) 293 .fontSize(16) 294 .textAlign(TextAlign.Center) 295 .margin({ top: 10 }) 296 }, (item: string) => item) 297 }.width('100%') 298 } 299 .scrollable(ScrollDirection.Vertical) // The scrollbar scrolls in the vertical direction. 300 .scrollBar(BarState.On) // The scrollbar is always displayed. 301 .scrollBarColor(Color.Gray) // The scrollbar color is gray. 302 .scrollBarWidth(10) // The scrollbar width is 10. 303 .friction(0.6) 304 .edgeEffect(EdgeEffect.None) 305 .onScroll((xOffset: number, yOffset: number) => { 306 console.info(xOffset + ' ' + yOffset) 307 }) 308 .onScrollEdge((side: Edge) => { 309 console.info('To the edge') 310 }) 311 .onScrollStop(() => { 312 console.info('Scroll Stop') 313 }) 314 315 Button('scroll 150') 316 .height('5%') 317 .onClick(() => { // Click to scroll down by 150.0 vp. 318 this.scroller.scrollBy(0, 150) 319 }) 320 .margin({ top: 10, left: 20 }) 321 Button('scroll 100') 322 .height('5%') 323 .onClick(() => { // Click to scroll down by 100.0 vp. 324 const yOffset: number = this.scroller.currentOffset().yOffset; 325 this.scroller.scrollTo({ xOffset: 0, yOffset: yOffset + 100 }) 326 }) 327 .margin({ top: 60, left: 20 }) 328 Button('scroll 100') 329 .height('5%') 330 .onClick(() => {// Click to scroll down by 100.0 vp. An animation is applied to the scrolling. 331 let curve = Curves.interpolatingSpring(10, 1, 228, 30) // Create a step curve. 332 const yOffset: number = this.scroller.currentOffset().yOffset; 333 this.scroller.scrollTo({ xOffset: 0, yOffset: yOffset + 100, animation: { duration: 1000, curve: curve } }) 334 }) 335 .margin({ top: 110, left: 20 }) 336 Button('back top') 337 .height('5%') 338 .onClick(() => { // Click to go back to the top. 339 this.scroller.scrollEdge(Edge.Top) 340 }) 341 .margin({ top: 160, left: 20 }) 342 Button('next page') 343 .height('5%') 344 .onClick(() => { // Click to go to the next page. 345 this.scroller.scrollPage({ next: true }) 346 }) 347 .margin({ top: 210, left: 20 }) 348 }.width('100%').height('100%').backgroundColor(0xDCDCDC) 349 } 350} 351``` 352 353 354 355### Example 2 356```ts 357@Entry 358@Component 359struct NestedScroll { 360 @State listPosition: number = 0; // 0 indicates scrolling to the top of the list, 1 indicates scrolling to the middle of the list, and 2 indicates scrolling to the bottom of the list. 361 private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 362 private scrollerForScroll: Scroller = new Scroller() 363 private scrollerForList: Scroller = new Scroller() 364 365 build() { 366 Flex() { 367 Scroll(this.scrollerForScroll) { 368 Column() { 369 Text("Scroll Area") 370 .width("100%") 371 .height("40%") 372 .backgroundColor(0X330000FF) 373 .fontSize(16) 374 .textAlign(TextAlign.Center) 375 .onClick(() => { 376 this.scrollerForList.scrollToIndex(5) 377 }) 378 379 List({ space: 20, scroller: this.scrollerForList }) { 380 ForEach(this.arr, (item: number) => { 381 ListItem() { 382 Text("ListItem" + item) 383 .width("100%") 384 .height("100%") 385 .borderRadius(15) 386 .fontSize(16) 387 .textAlign(TextAlign.Center) 388 .backgroundColor(Color.White) 389 }.width("100%").height(100) 390 }, (item: string) => item) 391 } 392 .width("100%") 393 .height("50%") 394 .edgeEffect(EdgeEffect.None) 395 .friction(0.6) 396 .onReachStart(() => { 397 this.listPosition = 0 398 }) 399 .onReachEnd(() => { 400 this.listPosition = 2 401 }) 402 .onScrollFrameBegin((offset: number) => { 403 if ((this.listPosition == 0 && offset <= 0) || (this.listPosition == 2 && offset >= 0)) { 404 this.scrollerForScroll.scrollBy(0, offset) 405 return { offsetRemain: 0 } 406 } 407 this.listPosition = 1 408 return { offsetRemain: offset }; 409 }) 410 411 Text("Scroll Area") 412 .width("100%") 413 .height("40%") 414 .backgroundColor(0X330000FF) 415 .fontSize(16) 416 .textAlign(TextAlign.Center) 417 } 418 } 419 .width("100%").height("100%") 420 }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20) 421 } 422} 423``` 424 425 426 427### Example 3 428```ts 429@Entry 430@Component 431struct StickyNestedScroll { 432 @State arr: number[] = [] 433 434 @Styles 435 listCard() { 436 .backgroundColor(Color.White) 437 .height(72) 438 .width("100%") 439 .borderRadius(12) 440 } 441 442 build() { 443 Scroll() { 444 Column() { 445 Text("Scroll Area") 446 .width("100%") 447 .height("40%") 448 .backgroundColor('#0080DC') 449 .textAlign(TextAlign.Center) 450 Tabs({ barPosition: BarPosition.Start }) { 451 TabContent() { 452 List({ space: 10 }) { 453 ForEach(this.arr, (item: number) => { 454 ListItem() { 455 Text("item" + item) 456 .fontSize(16) 457 }.listCard() 458 }, (item: string) => item) 459 }.width("100%") 460 .edgeEffect(EdgeEffect.Spring) 461 .nestedScroll({ 462 scrollForward: NestedScrollMode.PARENT_FIRST, 463 scrollBackward: NestedScrollMode.SELF_FIRST 464 }) 465 }.tabBar("Tab1") 466 467 TabContent() { 468 }.tabBar("Tab2") 469 } 470 .vertical(false) 471 .height("100%") 472 }.width("100%") 473 } 474 .edgeEffect(EdgeEffect.Spring) 475 .friction(0.6) 476 .backgroundColor('#DCDCDC') 477 .scrollBar(BarState.Off) 478 .width('100%') 479 .height('100%') 480 } 481 482 aboutToAppear() { 483 for (let i = 0; i < 30; i++) { 484 this.arr.push(i) 485 } 486 } 487} 488``` 489 490### Example 4 491```ts 492@Entry 493@Component 494struct Index { 495 scroller: Scroller = new Scroller; 496 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 497 build() { 498 Scroll(this.scroller) { 499 Column() { 500 ForEach(this.arr, (item: number) => { 501 Text(item.toString()) 502 .width('90%') 503 .height(200) 504 .backgroundColor(0xFFFFFF) 505 .borderWidth(1) 506 .borderColor(Color.Black) 507 .borderRadius(15) 508 .fontSize(16) 509 .textAlign(TextAlign.Center) 510 }, (item: string) => item) 511 }.width('100%').backgroundColor(0xDCDCDC) 512 } 513 .backgroundColor(Color.Yellow) 514 .height('100%') 515 .edgeEffect(EdgeEffect.Spring) 516 .scrollSnap({snapAlign:ScrollSnapAlign.START, snapPagination:400, enableSnapToStart:true, enableSnapToEnd:true}) 517 } 518} 519``` 520 521