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

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%');
  }
}

zhongcx
1 声望3 粉丝