【HarmonyOS】自定义TabLayout示例

【HarmonyOS】自定义TabLayout代码示例,通过 Scroll 锚点 Tab 布局,滚动条会自动滚动使选中的标签居中显示。

cke_147.gif

复制代码
class MyTabItem {
  label: string = "";
  positionX: number = -1; // 当前位置
  width: number = -1; // 当前宽度

  constructor(label: string) {
    this.label = label;
  }
}

@Component
struct MyTabLayout {
  onSelected?: (selectedIndex: number) => void;
  scroller: Scroller = new Scroller();
  @Prop tabItems: MyTabItem[];
  @State @Watch('selectIndexChanged') selectedIndex: number = 0;
  @State tabBarWidth: number = 0; // Tab 栏宽度

  selectIndexChanged() {
    if (this.onSelected) {
      this.onSelected(this.selectedIndex);
    }
  }

  build() {
    Column() {
      Scroll(this.scroller) {
        Row() {
          ForEach(this.tabItems, (item: MyTabItem, index: number) => {
            Row() {
              Image($r('app.media.app_icon')).width('44lpx').height('44lpx');
              Text(item.label)
                .margin({ left: '16lpx' })
                .fontColor(index === this.selectedIndex ? "#FF1919" : "#2E2E2E")
                .fontSize('30lpx');
            }.padding({ right: '16lpx' })
            .onAreaChange((previousArea: Area, currentArea: Area) => {
              if (item.positionX === -1) {
                item.positionX = currentArea.position.x as number;
              }
              if (item.width === -1) {
                item.width = currentArea.width as number;
              }
            })
            .onClick(() => {
              this.selectedIndex = index;

              this.scroller.scrollTo({
                xOffset: (item.positionX - this.tabBarWidth / 2 + item.width / 2),
                yOffset: 0,
                animation: true
              });
            });
          });
        }.height('95lpx');
      }
      .scrollable(ScrollDirection.Horizontal)
      .scrollBar(BarState.Off)
      .borderWidth({ bottom: 1 })
      .borderColor("#e3e3e3")
      .align(Alignment.Start)
      .width('100%')
      .onAreaChange((previousArea: Area, currentArea: Area) => {
        this.tabBarWidth = currentArea.width as number;
      });
    }
  }
}

@Entry
@Component
struct Page11 {
  scroller: Scroller = new Scroller();
  @State tabItems: MyTabItem[] = [];
  @State selectedIndex: number = 0

  getRandomInt(min: number, max: number): number {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  aboutToAppear(): void {
    for (let i = 0; i < 20; i++) {
      this.tabItems.push(new MyTabItem(`项目:${this.getRandomInt(1, 10000)}`));
    }
  }

  build() {
    Column() {
      MyTabLayout({
        tabItems: this.tabItems,
        onSelected: (selectedIndex: number) => {
          console.info(`当前选择的位置: ${selectedIndex}`);
          this.selectedIndex = selectedIndex
        }
      });
      Stack() {
        Text(`当前选择的位置:${this.selectedIndex}`)
      }.width('100%')
      .layoutWeight(1)
      .backgroundColor(Color.Orange)
    }
    .height('100%')
    .width('100%');
  }
}
复制代码

 

posted @   zhongcx  阅读(17)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示