• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![en-us_image_0000001174104386](figures/en-us_image_0000001174104386.gif)
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![NestedScroll](figures/NestedScroll.gif)
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![NestedScroll2](figures/NestedScroll2.gif)
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![NestedScrollSnap](figures/NestedScrollSnap.gif)
521