DEV Community

Cover image for HarmonyOS Development: Use nestedScroll to resolve sliding conflicts
程序员一鸣
程序员一鸣

Posted on

HarmonyOS Development: Use nestedScroll to resolve sliding conflicts

Foreword 

this article is based on Api13 

in actual development, sliding conflicts are inevitable and are common in the nested use of scrollable container components, such the Scroll component nests the List component, the List component nests the Grid component, and so on. As long as the Scroll container component is nested, the tiresome sliding conflict will come on your face, which is very maddening. How to deal with sliding conflicts has become a required course in development. However, the processing method in Hongmeng seems more intuitive and simple compared with Android. It can be done by using one attribute, that is nestedScroll. 

Simple Case 

the case is very simple. The outer layer is a Scroll Scroll container, and there is also a List component Scroll component inside. There is a common component on the List.

 

@Entry
@Component
struct Index {
  build() {
    Scroll() {
      Column() {
        Text("我是顶部的组件")
          .width("100%")
          .height(200)
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Pink)
          .fontColor(Color.White)

        List() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (item: number) => {
            ListItem() {
              Text(item.toString())
                .width("100%")
                .height(80)
                .textAlign(TextAlign.Center)
            }
          })
        }
        .width("100%")
        .height("100%")
        .scrollBar(BarState.Off)
        .divider({ color: Color.Gray, strokeWidth: 1 })
        .edgeEffect(EdgeEffect.None)

      }
    }.width("100%")
    .height("100%")
    .scrollBar(BarState.Off)
  }
}
Enter fullscreen mode Exit fullscreen mode

The effect is as follows: 

Image description

the effect we want is to let the top component scroll up first, and then scroll the List component below. We run to see the effect: 

Image description

obviously, our effect has not been achieved, which is caused by sliding conflicts. In this case, the List component, as a subcomponent, must first hand over the sliding event to the Scroll component, and then hand over the sliding event to itself after the Scroll component rolls to the edge. This process is also correct. How to do it? As mentioned earlier, that is the nestedScroll attribute. 

Each scroll container component has a nestedScroll attribute, which mainly solves sliding conflicts in nested scroll mode. We set the List component with the following code:

 

.nestedScroll({
          scrollForward: NestedScrollMode.PARENT_FIRST,
          scrollBackward: NestedScrollMode.SELF_FIRST
        })
Enter fullscreen mode Exit fullscreen mode

after setting up, look at the effect again:

Image description

It can be seen that the sliding conflict has been perfectly solved and the desired effect has been achieved. 

Understanding nestedScroll 

through the case in the foreword, we have basically known the purpose of the nestedScroll property, primarily, it is used to set nested scrolling options and nested scrolling modes in both front and back directions to realize scrolling linkage with the parent component. 

Image description

Let's focus on the parameter NestedScrollOptions, which has two values, scrollForward and scrollBackward, one for scrolling to the end and the other for scrolling to the beginning. 

Image description

Both parameters have a common value type the NestedScrollMode has the following values to choose from: 

name  description 
SELF_ONLY  scrolls only by itself, not with the parent component. 
SELF_FIRST  scrolls itself first, and scrolls itself to the edge before the parent component scrolls. After the parent component scrolls to the edge, if the parent component has an edge effect, the parent component triggers the edge effect, otherwise the child component triggers the edge effect. 
PARENT_FIRST  the parent component scrolls first, and the parent component scrolls to the edge and then scrolls itself. After scrolling to the edge, if there is an edge effect, it will trigger its own edge effect, otherwise it will trigger the edge effect of the parent component.
PARALLEL  both itself and the parent component scroll at the same time. After both itself and the parent component reach the edge, if it has an edge effect, it triggers the edge effect itself, otherwise the parent component triggers the edge effect. 

Examples of use 

in the preface, we simply used the Scroll component to nest the List component as an example. Let's look at a case of the Scroll component nesting the Web component.

 

import webview from '@ohos.web.webview'

@Entry
@Component
struct Index {
  private controller: webview.WebviewController = new webview.WebviewController()

  build() {

    Scroll() {
      Column() {
        Text("我是顶部的组件")
          .width("100%")
          .height(200)
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Pink)
          .fontColor(Color.White)

        Web({
          src: "https://juejin.cn/user/1398234520239095/columns",
          controller: this.controller
        })
          .nestedScroll({
            scrollForward: NestedScrollMode.PARENT_FIRST,
            scrollBackward: NestedScrollMode.SELF_FIRST
          })

      }
    }.width("100%")
    .height("100%")
    .scrollBar(BarState.Off)

  }
}
Enter fullscreen mode Exit fullscreen mode

The above effect is basically the same as that in the foreword, and the effect is no longer pasted. In fact, no matter how many cases are, they are basically the same, except that the values in nestedScroll are different. 

Related Summary 

in actual development, it is far more complicated than the previous case. For example, the refresh Library I packaged earlier has a refresh head on the scroll component and a load tail on the bottom. There are also more complicated ones, such as list ceiling operation. A nestedScroll attribute is far from enough. It is often combined with sliding monitoring, whether to scroll to the top and tail, etc. to achieve our actual effect. 

For example, in the above case, we add a bottom component under the List component, and we run to see the effect: 

obviously, the previously configured nestedScroll attribute only satisfies the top component, while the bottom component obviously has sliding conflicts during the sliding process, which does not meet our expectation. In fact, for the bottom, sliding up is to roll itself first and then roll the parent component, while sliding down is to roll the parent component first and then roll its own component. 

Image description

In view of the above problems, there are actually many ways to deal with them. The simplest one is that the bottom component is under the last component and is treated as part of the List component. Of course, the top component can also do the same, so there is no sliding conflict.

 

if (index == this.dataArray.length - 1) {
                Column() {
                  Text(item.toString())
                    .width("100%")
                    .height(80)
                    .textAlign(TextAlign.Center)

                  Text("我是底部的组件")
                    .width("100%")
                    .height(200)
                    .textAlign(TextAlign.Center)
                    .backgroundColor(Color.Pink)
                    .fontColor(Color.White)
                }

  }
Enter fullscreen mode Exit fullscreen mode

Let's look at the effect:

Image description

There is a problem with adding components to the position of the head and tail data, for example, what if there is no data? The top component and the bottom component cannot be displayed. For example, what if a Grid component or other scroll component is not loaded instead of a List component? Obviously there is a big problem with the handling. 

This homework is left to friends. Do you know how to solve it? 

This article tags: HarmonyOS/ArkUI/sliding conflict

Top comments (0)