HarmonyOS鸿蒙Next中使用nestedScroll进行吸顶时,内层的list内容显示不全,不能给list加layoutWeight(1),如何解决

HarmonyOS鸿蒙Next中使用nestedScroll进行吸顶时,内层的list内容显示不全,不能给list加layoutWeight(1),如何解决

@Entry
@Component
struct Index {
  build() {
    Scroll() {
      Column() {
        Text('其他UI内容')
          .width('100%')
          .height(850)
          .textAlign(TextAlign.Center)
          .backgroundColor('#c900f7ff')
        Column() {
          Text('这是吸顶标题')
            .width('100%')
            .height(50)
            .fontSize(20)
            .textAlign(TextAlign.Center)
            .backgroundColor('#1f000000')
          List({ space: 5 }) {
            ForEach(Array.from({ length: 1 }), (item: undefined, index: number) => {
              ListItem() {
                Text('这是列表项')
              }
              .width('100%')
              .height(50)
              .padding({ left: 5, right: 5 })
              .backgroundColor('#aeefc901')
            })
          }
          .layoutWeight(1)
          .alignListItem(ListItemAlign.Center)
          .nestedScroll({
            scrollForward: NestedScrollMode.PARENT_FIRST,
            scrollBackward: NestedScrollMode.SELF_FIRST
          })
        }
        .constraintSize({ maxHeight: '100%' })
      }
    }
    .width('100%')
    .height('100%')
    .align(Alignment.Top)
  }
}

更多关于HarmonyOS鸿蒙Next中使用nestedScroll进行吸顶时,内层的list内容显示不全,不能给list加layoutWeight(1),如何解决的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

问题描述

如何在HarmonyOS中实现标题吸顶效果?

背景知识

吸顶效果(Sticky Effect 或 Fixed on Scroll)是网页开发中的一种常见交互设计,指当用户滚动页面时,某个元素(如导航栏、标题栏、工具栏等)会固定在浏览器窗口的顶部(或其他指定位置),保持始终可见,不会随着页面滚动而消失。这种效果能提升用户体验,方便用户快速访问关键功能(如购物商城导航菜单、返回顶部按钮等)。在开发过程中,吸顶效果通常用于需要保持关键元素始终可见的场景,以提升用户体验和操作效率。以下是一些典型应用场景及具体需求:

  • 导航栏场景:电商网站顶部分类导航、博客网站的目录跳转;
  • 长表格的表头:金融数据报表、后台管理系统中的列表页;
  • 分类筛选栏:电商商品列表的“价格排序”、内容平台的“标签筛选”;
  • 广告或通知栏:持续展示广告场景。

在HarmonyOS中有多种实现吸顶效果的方案,以及不同的吸顶效果,不同方案及需要了解的知识如下:

  • 普通吸顶效果:标题一直附着在页面顶部或底部,不随着页面滚动:

  • 滚动嵌套吸顶效果:标题本身在滚动组件内部,能跟随滚动组件移动。同时在滚动到顶部时,吸附在顶部,不随后续滚动消失:

    1. 通过父子组件的滚动联动实现吸顶效果。
    • 父子组件的滚动联动效果实现,由滚动通用属性[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list#nestedscroll10” target="_blank"]nestedScroll属性[/a]控制。nestedScroll属性的参数NestedScrollMode分为以下四类:

      参数类型 效果
      SELF_ONLY 只自身滚动,不与父组件联动。
      SELF_FIRST 自身先滚动,自身滚动到边缘以后父组件滚动。父组件滚动到边缘以后,如果父组件有边缘效果,则父组件触发边缘效果,否则子组件触发边缘效果。
      PARENT_FIRST 父组件先滚动,父组件滚动到边缘以后自身滚动。自身滚动到边缘后,如果有边缘效果,会触发自身的边缘效果,否则触发父组件的边缘效果。
      PARALLEL 自身和父组件同时滚动,自身和父组件都到达边缘以后,如果自身有边缘效果,则自身触发边缘效果,否则父组件触发边缘效果。
    1. 通过[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list” target="_blank"]List组件[/a]的[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list#sticky9” target="_blank"]sticky[/a]属性实现吸顶效果。
    • 该方案需要配合[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-listitemgroup” target="_blank"]ListItemGroup组件[/a]使用,设置ListItemGroup中header和footer是否要吸顶或吸底。sticky属性参数类型如下:

      类型 效果
      StickyStyle.None 0 ListItemGroup的header不吸顶,footer不吸底。
      StickyStyle.Header 1 ListItemGroup的header吸顶,footer不吸底。
      StickyStyle.Footer 2 ListItemGroup的footer吸底,header不吸顶。

解决方案

  • 普通吸顶效果:

    • 方案一:通过Tabs组件的tabBar属性实现吸顶效果。在实施过程中有时我们也可以自定义实现Tabs效果。
      @Entry
      @Component
      export struct Index {
        subsController: TabsController = new TabsController()
        @State arr: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']
        
        build() {
          Tabs({
            barPosition: BarPosition.Start,
            controller: this.subsController
          }){
            TabContent(){
              List({ space: 10 }){
                ForEach(this.arr, (item: number) => {
                  ListItem(){
                    Row(){
                      Text('item' + item)
                        .fontSize(16)
                        .height(72)
                        .fontColor(Color.Black)
                    }
                    .width('100%')
                    .height(72)
                    .justifyContent(FlexAlign.Center)
                  }
                  .borderRadius(15)
                  .backgroundColor(Color.White)
                }, (item: string) => item)
              }
              .padding({ left: 10, right: 10 })
              .width('100%')
              .height('100%')
              .scrollBar(BarState.Off)
            }
            .tabBar('关注')
            .backgroundColor(Color.Gray)
            
            TabContent(){
              Text('推荐')
            }
            .tabBar('推荐')
            .backgroundColor(Color.White)
          }
          .backgroundColor('#6dbab8b8')
        }
      }
      
    • 方案二:自定义标题的吸顶实现,该方案在实际软件中若要实现Tabs页面切换效果,需要自定义页面切换逻辑(页面切换与本知识无关,不再赘述)。
      @Entry
      @Component
      struct ScrollerTest {
        subsController: TabsController = new TabsController()
        @State arr: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']
        
        build() {
          Column() {
            Row() {
              // 吸顶标题
              Text('自定义占位标题')
                .width('100%')
                .height(60)
                .backgroundColor('#ff736c6c')
            }
            List({ space: 10 }){
              // ...
            }
            .layoutWeight(1) // 更换List组件height属性,高度限制以layoutWeight(1)的形式自动填充父组件高度
          }
          .width('100%')
          .height('100%') // 普通吸顶效果时,滚动组件的父组件可以不设置高度,但是滚动嵌套吸顶时一定要设置高度限制为100%
          .backgroundColor('#6dbab8b8')
        }
      }
      
  • 单标题滚动嵌套吸顶效果:

    • 通过nestedScroll属性,实现吸顶效果。由于nestedScroll属性是滚动与滑动组件的通用属性,理论上在滚动组件嵌套的过程中,支持该属性的滚动组件都可以实现吸顶效果。以Tabs组件为例,参考代码如下:
      @Entry
      @Component
      struct ScrollerTest {
        subsController: TabsController = new TabsController()
        @State arr: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']
        
        build() {
          Scroll() {
            Column() {
              Column() {
                Text('广告展示/搜索选择等')
                  .fontSize(30)
                  .width('100%')
                  .height(200)
                  .backgroundColor('#ff0296a4')
                  .textAlign(TextAlign.Center)
              }
              Tabs({ barPosition: BarPosition.Start, controller: this.subsController }) {
                TabContent() {
                  List({ space: 10 }){
                    ForEach(this.arr, (item: number) => {
                      ListItem(){
                        Row(){
                          Text('item' + item)
                            .fontSize(16)
                            .height(72)
                            .fontColor(Color.Black)
                        }
                        .width('100%')
                        .height(72)
                        .justifyContent(FlexAlign.Center)
                      }
                      .borderRadius(15)
                      .backgroundColor(Color.White)
                    }, (item: string) => item)
                  }
                  .padding({ left: 10, right: 10 })
                  .width('100%')
                  .height('100%')
                  .scrollBar(BarState.Off)
                  .nestedScroll({
                    scrollForward: NestedScrollMode.PARENT_FIRST, // 向上滚动PARENT_FIRST:父组件先滚动,父组件滚动到边缘以后自身滚动。
                    scrollBackward: NestedScrollMode.SELF_FIRST // 向下滚动SELF_FIRST:自身先滚动,自身滚动到边缘以后父组件滚动。
                  })
                }
                .tabBar('关注')
                .backgroundColor(Color.Gray)
                
                TabContent(){
                  Text('推荐')
                }
                .tabBar('推荐')
                .backgroundColor(Color.White)
              }
              .backgroundColor('#6dbab8b8')
            }
          }
          .width('100%')
          .edgeEffect(EdgeEffect.Spring)
          .friction(0.6)
          .backgroundColor(Color.White)
          .scrollBar(BarState.Off)
          .width('100%')
          .height('100%')
        }
      }
      
  • 多标题滚动嵌套吸顶效果

    • 方案一:通过nestedScroll属性对滚动组件多次滚动嵌套,参考单标题滚动嵌套吸顶效果,修改的核心代码如下:

      @Entry
      @Component
      struct ScrollerTest {
        subsController: TabsController = new TabsController()
        @State arr: string[] = ['1', '2', '3']
        @State arr1: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']
        
        build() {
          Scroll() {
            Column() {
              // ...(省略广告展示/搜索选择标题部分代码)
              Column() {
                Row() {
                  Text('自定义标题占位') // 自定义实现标题吸顶,依旧采用Tabs组件也适用
                    .fontSize(16)
                    .height(60)
                    .width('100%')
                }
                Scroll() {
                  Column() {
                    ForEach(this.arr, (item: number) => {
                      Row() {
                        Text('item' + item)
                          .fontSize(16)
                          .height(72)
                          .fontColor(Color.Black)
                      }
                      .width('100%')
                      .height(72)
                      .borderRadius(15)
                      .margin({
                        bottom: 10
                      })
                      .justifyContent(FlexAlign.Center)
                    }, (item: string) => item)
                    // ...(省略单标题滚动嵌套吸顶效果代码中Tabs组件代码)
                  }
                  .backgroundColor(Color.White)
                  .width('100%')
                }
                .width('100%')
                .height('100%')
                .scrollBar(BarState.Off)
                .nestedScroll({
                  scrollForward: NestedScrollMode.PARENT_FIRST, // 向上滚动PARENT_FIRST:父组件先滚动,父组件滚动到边缘以后自身滚动。
                  scrollBackward: NestedScrollMode.SELF_FIRST // 向下滚动SELF_FIRST:自身先滚动,自身滚动到边缘以后父组件滚动。
                })
              }
              .height('100%') // 由于是自定义的标题,所以容纳标题和列表的父组件一定要设置高度为100%
              .backgroundColor('#6dbab8b8')
            }
          }
          .width('100%')
        }
        // ...
      }
      
    • 方案二:通过List组件的sticky属性,实现吸顶效果。

      • 该方案仅适用于List组件,具体实施方案参考官方示例:吸顶/吸底

常见FAQ

Q:还有其他组件能实现吸顶效果吗? A:可以通过[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-stack” target="_blank"]Stack组件[/a]或者[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-z-order#zindex” target="_blank"]zIndex[/a]属性,这类层叠布局实现组件吸顶。但这类层叠方式,该场景下并不常见,该方式更多用于网页中的客服按钮/回到页面顶部等场景。

Q:如何实现滑动时吸顶标题组件颜色渐变的效果? A:可以通过[a href=“https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-scrollable-common#ondidscroll12” target="_blank"]onDidScroll[/a]等监听滑动的事件,监听组件的偏移量,从而控制吸顶的标题组件改变透明度、背景颜色等状态。

总结

分类 普通吸顶效果 单标题滚动嵌套吸顶效果 多标题滚动嵌套吸顶效果
实现方式 Tabs或自定义标题栏 nestedScroll属性滚动嵌套Tabs或自定义标题栏 nestedScroll属性滚动嵌套Tabs或自定义标题栏/List组件的sticky属性
自定义吸顶标题时易错问题 自定义标题栏时Scroll等滚动组件没有设置高度限制导致滚动组件超出安全区。其最大自适应高度为屏幕的百分百高度,可以设置heght属性或者layoutWeight(1)属性限制高度。 滚动组件的父组件一定要设置高度限制为100%,若不设置高度限制,父组件自适应高度会导致吸顶失效,因为滚动组件的最大自适应高度为屏幕的100%高度,当滚动组件子组件高度和大于屏幕的百分百时,滚动组件高度自适应100%高度,会将标题顶出屏幕外,导致吸顶失效。 当采用nestedScroll属性滚动嵌套实现时,与“单标题滚动嵌套吸顶效果”需要注意相似问题。
适用场景 适用于所有的带标题的软件场景 微信朋友圈等类似场景 电商软件主页场景

更多关于HarmonyOS鸿蒙Next中使用nestedScroll进行吸顶时,内层的list内容显示不全,不能给list加layoutWeight(1),如何解决的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


您好,为了更快速解决您的问题,并且吸引更多用户一同参与您问题的解答与讨论,建议您补全如下信息:

补全复现代码(如最小复现demo、脚本),让参与用户更快速复现您的问题;

更多提问技巧,请参考:《提问小技巧:让解答更高效》

在HarmonyOS Next中,使用nestedScroll实现吸顶效果时,若list内容显示不全且无法使用layoutWeight(1),可通过设置list的固定高度解决。使用onSizeChange回调动态计算剩余屏幕高度,将结果赋给list的height属性。或改用Scroll嵌套Column布局,将list作为Column的子组件,通过scrollContent参数控制滚动区域。确保list的scrollBar属性设置为true以显示完整内容。

在HarmonyOS Next中,当使用nestedScroll实现吸顶效果时,List内容显示不全的问题可以通过以下方式解决:

  1. 移除constraintSize约束,改用flex布局:
Column() {
  Text('这是吸顶标题')
    // ...其他样式
  List({ space: 5 }) {
    // ...列表内容
  }
  .width('100%')
  .height('100%')  // 关键修改点
  .nestedScroll({
    scrollForward: NestedScrollMode.PARENT_FIRST,
    scrollBackward: NestedScrollMode.SELF_FIRST
  })
}
  1. 如果必须使用constraintSize,可以改为设置minHeight而非maxHeight
.constraintSize({ minHeight: '100%' })
  1. 确保父容器Scroll有明确的高度约束,如:
Scroll() {
  // 内容
}
.height('100%')

这些修改能让List获得正确的布局空间,同时保持nestedScroll的吸顶效果。注意在Column容器中,子组件默认是垂直排列的,合理设置高度是关键。

回到顶部