当前位置:   article > 正文

【HarmonyOS NEXT】如何实现Scroll容器组件中子组件吸顶效果

【HarmonyOS NEXT】如何实现Scroll容器组件中子组件吸顶效果

 【关键字】

Scroll / 子组件 / 吸顶

【问题描述】

垂直滑动的Scroll容器组件中,自上而下依次包含Text1、Text2、List三个子组件,然后上滑Scroll组件,滑至Text2子组件处,Text2吸顶,List子组件中内容可继续滑动。

请问此场景下Text2吸顶效果可如何实现?鸿蒙原生有提供吸顶效果的API吗?

【解决方案】

暂时没有原生的吸顶效果API,可以通过偏移量来实现相同效果。

具体Demo如下:

  1. enum ScrollPosition {
  2. start,
  3. center,
  4. end
  5. }
  6. class ItemClass {
  7. content: string = '';
  8. color: Color = Color.White;
  9. }
  10. @Entry
  11. @Component
  12. struct NestedScrollDemo {
  13. @State listPosition: number = ScrollPosition.start; // 0代表滚动到List顶部,1代表中间值,2代表滚动到List底部。
  14. @State scrollPosition: number = ScrollPosition.start; // 0代表滚动到页面顶部,1代表中间值,2代表滚动到页面底部。
  15. @State showTitle: boolean = false;
  16. @State currentYOffset: number = 0;
  17. private arr: ItemClass[] = [];
  18. private colorArr: Color[] = [Color.White, Color.Blue, Color.Brown, Color.Green, Color.Gray];
  19. private scrollerForScroll: Scroller = new Scroller();
  20. private scrollerForList: Scroller = new Scroller();
  21. private scrollerForTitle: Scroller = new Scroller();
  22. @State currentIndex: number = 0;
  23. aboutToAppear() {
  24. for (let i = 0; i < 6; i++) {
  25. let data: ItemClass = {
  26. content: i.toString(),
  27. color: this.colorArr[i % 5]
  28. }
  29. this.arr.push(data);
  30. }
  31. }
  32. @Builder
  33. myBuilder() {
  34. Row() {
  35. List({ space: 2, initialIndex: 0, scroller: this.scrollerForTitle }) {
  36. ForEach(this.arr, (item: ItemClass, index) => {
  37. ListItem() {
  38. Column() {
  39. Text(item.content);
  40. Divider()
  41. .color('#000000')
  42. .strokeWidth(5)
  43. .visibility(index == this.currentIndex ? Visibility.Visible : Visibility.Hidden)
  44. }
  45. .width('25%')
  46. .height(50)
  47. .onClick(() => {
  48. this.scrollerForList.scrollToIndex(index)
  49. this.scrollerForScroll.scrollEdge(Edge.Bottom)
  50. })
  51. }
  52. })
  53. }
  54. .listDirection(Axis.Horizontal)
  55. .scrollBar(BarState.Off)
  56. }
  57. .backgroundColor('#ffe2d0d0')
  58. .alignItems(VerticalAlign.Center)
  59. }
  60. build() {
  61. Stack({ alignContent: Alignment.Top }) {
  62. Scroll(this.scrollerForScroll) {
  63. Column() {
  64. Image($r('app.media.app_icon'))
  65. .width("100%")
  66. .height("40%")
  67. this.myBuilder();
  68. List({ space: 10, scroller: this.scrollerForList }) {
  69. ForEach(this.arr, (item: ItemClass, index) => {
  70. ListItem() {
  71. Column() {
  72. Text(item.content)
  73. //添加其他内容
  74. }
  75. .width('100%')
  76. .height(500)
  77. .backgroundColor(item.color)
  78. }.width("100%").height(500)
  79. .onVisibleAreaChange([0.8], (isVisible) => {
  80. if (isVisible) {
  81. this.currentIndex = index;
  82. this.scrollerForTitle.scrollToIndex(this.currentIndex);
  83. }
  84. })
  85. }, (item: ItemClass) => item.content)
  86. }
  87. .padding({ left: 10, right: 10 })
  88. .width("100%")
  89. .edgeEffect(EdgeEffect.None)
  90. .scrollBar(BarState.Off)
  91. .onReachStart(() => {
  92. this.listPosition = ScrollPosition.start
  93. })
  94. .onReachEnd(() => {
  95. this.listPosition = ScrollPosition.end
  96. })
  97. .onScrollFrameBegin((offset: number, state: ScrollState) => {
  98. // 滑动到列表中间时
  99. if (!((this.listPosition == ScrollPosition.start && offset < 0)
  100. || (this.listPosition == ScrollPosition.end && offset > 0))) {
  101. this.listPosition = ScrollPosition.center
  102. }
  103. // 如果页面已滚动到底部,列表不在顶部或列表有正向偏移量
  104. if (this.scrollPosition == ScrollPosition.end
  105. && (this.listPosition != ScrollPosition.start || offset > 0)) {
  106. return { offsetRemain: offset };
  107. } else {
  108. this.scrollerForScroll.scrollBy(0, offset)
  109. return { offsetRemain: 0 };
  110. }
  111. })
  112. .width("100%")
  113. .height("calc(100% - 50vp)")
  114. .backgroundColor('#F1F3F5')
  115. }
  116. }
  117. .scrollBar(BarState.Off)
  118. .width("100%")
  119. .height("100%")
  120. .onScroll((xOffset: number, yOffset: number) => {
  121. this.currentYOffset = this.scrollerForScroll.currentOffset().yOffset;
  122. // 非(页面在顶部或页面在底部),则页面在中间
  123. if (!((this.scrollPosition == ScrollPosition.start && yOffset < 0)
  124. || (this.scrollPosition == ScrollPosition.end && yOffset > 0))) {
  125. this.scrollPosition = ScrollPosition.center
  126. }
  127. })
  128. .onScrollEdge((side: Edge) => {
  129. if (side == Edge.Top) {
  130. // 页面在顶部
  131. this.scrollPosition = ScrollPosition.start
  132. } else if (side == Edge.Bottom) {
  133. // 页面在底部
  134. this.scrollPosition = ScrollPosition.end
  135. }
  136. })
  137. .onScrollFrameBegin(offset => {
  138. if (this.scrollPosition == ScrollPosition.end) {
  139. return { offsetRemain: 0 };
  140. } else {
  141. return { offsetRemain: offset };
  142. }
  143. })
  144. }
  145. .width('100%')
  146. .height('100%')
  147. .backgroundColor(0xDCDCDC)
  148. }
  149. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/231508?site
推荐阅读
相关标签
  

闽ICP备14008679号