如何实现通用的吸顶效果

希望实现吸顶效果

HarmonyOS
2024-06-11 23:08:52
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
okmwq

list组件的sticky属性可以实现吸顶

相关Demo:

@Entry 
@Component 
struct ListStickyExample { 
  @State array: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
  @State alignListItem: ListItemAlign = ListItemAlign.Start 
  private titles: string[] = ['标题1', '标题2', '标题3', '标题4'] 
  private data: string[] = ['标题1', '标题2', '标题3', '标题4', '标题5', '标题6', '标题7', '标题8', '标题9', '标题10', '标题11', '标题12'] 
 
  @Builder 
  titleBuilder() { 
    Row({ space: 20 }) { 
      ForEach(this.titles, (item: string) => { 
        Text(item) 
          .width(100) 
          .textAlign(TextAlign.Center) 
      }, (item: number) => JSON.stringify(item)) 
    } 
    .width('100%') 
    .height(100) 
  } 
 
  @Builder 
  ListBuilder() { 
    Column() { 
      List() { 
        ListItemGroup({ header: this.titleBuilder() }) { 
          ForEach(this.array, (index: number) => { 
            ListItem() { 
              this.ListItemBuilder(this.data[index % 6]); 
            } 
          }, (item: string) => item) 
        } 
      } 
      .sticky(StickyStyle.Header) 
      .edgeEffect(EdgeEffect.None) 
      .listDirection(Axis.Vertical) 
    } 
  } 
 
  @Builder 
  ListItemBuilder(index: string) { 
    Row() { 
      Text(index).fontSize(20).height(100) 
    } 
  } 
 
  build() { 
    Column() { 
      this.ListBuilder() 
    } 
  } 
}

扩展需求:

1、标题栏吸顶

2、标题栏点击 跳转列表内容的某一标题

3、列表内容变更的时候,标题栏同步修改

扩展实现:

enum ScrollPosition { 
  start, 
  center, 
  end 
} 
 
class ItemClass { 
  content: string = ''; 
  color: Color = Color.White; 
} 
 
@Entry 
@Component 
struct NestedScroll { 
  @State listPosition: number = ScrollPosition.start; // 0代表滚动到List顶部,1代表中间值,2代表滚动到List底部。 
  @State scrollPosition: number = ScrollPosition.start; // 0代表滚动到页面顶部,1代表中间值,2代表滚动到页面底部。 
  @State showTitle: boolean = false; 
  @State currentYOffset: number = 0; 
  private arr: ItemClass[] = []; 
  private colorArr: Color[] = [Color.White, Color.Blue, Color.Brown, Color.Green, Color.Gray]; 
  private scrollerForScroll: Scroller = new Scroller(); 
  private scrollerForList: Scroller = new Scroller(); 
  private scrollerForTitle: Scroller = new Scroller(); 
  @State currentIndex: number = 0; 
 
  aboutToAppear() { 
    for(let i = 0; i < 6; i++) { 
      let data: ItemClass = { 
        content: i.toString(), 
        color: this.colorArr[i % 5] 
      } 
      this.arr.push(data); 
    } 
  } 
 
 
  @Builder myBuilder() { 
    Row() { 
      List({ space: 2, initialIndex: 0, scroller: this.scrollerForTitle }) { 
        ForEach(this.arr, (item: ItemClass, index) => { 
          ListItem() { 
            Column() { 
              Text(item.content); 
              Divider() 
                .color('#000000') 
                .strokeWidth(5) 
                .visibility(index == this.currentIndex ? Visibility.Visible : Visibility.Hidden) 
            } 
            .width('25%') 
            .height(50) 
            .onClick(() => { 
              this.scrollerForList.scrollToIndex(index) 
              this.scrollerForScroll.scrollEdge(Edge.Bottom) 
            }) 
          } 
        }) 
      } 
      .listDirection(Axis.Horizontal) 
      // 滚动条 
      .scrollBar(BarState.Off) 
    } 
    .backgroundColor('#ffe2d0d0') 
    .alignItems(VerticalAlign.Center) 
  } 
  build() { 
    Stack({ alignContent: Alignment.Top }) { 
      Scroll(this.scrollerForScroll) { 
        Column() { 
          Image($r('app.media.app_icon')) 
            .width("100%") 
            .height("40%") 
          this.myBuilder(); 
 
          // this.ListBuilder() 
 
          List({ space: 10, scroller: this.scrollerForList }) { 
            ForEach(this.arr, (item: ItemClass, index) => { 
              ListItem() { 
                Column() { 
                  Text(item.content) 
                  //添加其他内容 
                } 
                .width('100%') 
                .height(500) 
                .backgroundColor(item.color) 
              }.width("100%").height(500) 
              .onVisibleAreaChange([0.8], (isVisible) => { 
                if (isVisible) { 
                  this.currentIndex = index; 
                  this.scrollerForTitle.scrollToIndex(this.currentIndex); 
                } 
              }) 
            }, (item: ItemClass) => item.content) 
          } 
          .padding({ left: 10, right: 10 }) 
          .width("100%") 
          .edgeEffect(EdgeEffect.None) 
          .scrollBar(BarState.Off) 
          .onReachStart(() => { 
            this.listPosition = ScrollPosition.start 
          }) 
          .onReachEnd(() => { 
            this.listPosition = ScrollPosition.end 
          }) 
          .onScrollFrameBegin((offset: number, state: ScrollState) => { 
            // 滑动到列表中间时 
            if (!((this.listPosition == ScrollPosition.start && offset < 0) 
              || (this.listPosition == ScrollPosition.end && offset > 0))) { 
              this.listPosition = ScrollPosition.center 
            } 
 
            // 如果页面已滚动到底部,列表不在顶部或列表有正向偏移量 
            if (this.scrollPosition == ScrollPosition.end 
              && (this.listPosition != ScrollPosition.start || offset > 0)) { 
              return { offsetRemain: offset }; 
            } else { 
              this.scrollerForScroll.scrollBy(0, offset) 
              return { offsetRemain: 0 }; 
            } 
          }) 
          .width("100%") 
          // 吸顶效果 
          .height("calc(100% - 50vp)") 
          .backgroundColor('#F1F3F5') 
        } 
      } 
      .scrollBar(BarState.Off) 
      .width("100%") 
      .height("100%") 
      .onScroll((xOffset: number, yOffset: number) => { 
        this.currentYOffset = this.scrollerForScroll.currentOffset().yOffset; 
 
        // 非(页面在顶部或页面在底部),则页面在中间 
        if (!((this.scrollPosition == ScrollPosition.start && yOffset < 0) 
          || (this.scrollPosition == ScrollPosition.end && yOffset > 0))) { 
          this.scrollPosition = ScrollPosition.center 
        } 
      }) 
      .onScrollEdge((side: Edge) => { 
        if (side == Edge.Top) { 
          // 页面在顶部 
          this.scrollPosition = ScrollPosition.start 
        } else if (side == Edge.Bottom) { 
          // 页面在底部 
          this.scrollPosition = ScrollPosition.end 
        } 
      }) 
      .onScrollFrameBegin(offset => { 
        if (this.scrollPosition == ScrollPosition.end) { 
          return { offsetRemain: 0 }; 
        } else { 
          return { offsetRemain: offset }; 
        } 
      }) 
    } 
    .width('100%') 
    .height('100%') 
    .backgroundColor(0xDCDCDC) 
  } 
}
分享
微博
QQ
微信
回复
2024-06-12 23:07:31
相关问题
如何实现Tabs组件tarbar顶效果
139浏览 • 1回复 待解决
tabs结合scroll实现顶效果
334浏览 • 1回复 待解决
编写一个页面,实现顶效果
358浏览 • 1回复 待解决
如何实现分组列表顶/效果
763浏览 • 1回复 待解决
如何实现列表页单选效果
895浏览 • 0回复 待解决
canvas如何实现水印效果
357浏览 • 1回复 待解决
如何实现类似keyframes效果
648浏览 • 1回复 待解决
如何实现组件阴影效果
329浏览 • 1回复 待解决
应用通用获焦及走焦方式如何实现
508浏览 • 1回复 待解决
滑动组件如何实现单边spring效果
489浏览 • 1回复 待解决
如何实现图片大图预览效果
477浏览 • 1回复 待解决
如何等效实现JSONObejct效果
214浏览 • 1回复 待解决
图片模糊效果如何实现
314浏览 • 1回复 待解决
openharmony ets和js Api能否实现通用
4172浏览 • 1回复 待解决
如何实现视频滤镜效果
621浏览 • 1回复 待解决
如何实现动画转场效果
357浏览 • 1回复 待解决
文字动画效果如何实现
629浏览 • 0回复 待解决
如何实现全局浮窗效果
582浏览 • 1回复 待解决
页面和列表嵌套滚动,实现列表
443浏览 • 1回复 待解决