DEV Community

HarmonyOS
HarmonyOS

Posted on

How to Display Only the Content Page Corresponding to the Tab

Read the original article:How to Display Only the Content Page Corresponding to the Tab

How to Display Only the Content Page Corresponding to the Tab

Context

In the Tabs component, due to the built-in sliding animation for page switching, when clicking on the tabBar to switch pages, the transition slides from the current page to the target page. This causes the intermediate pages between the current and target pages to also be loaded.

Description

In the Tabs component, due to the built-in sliding animation for page switching, clicking the tabBar to switch pages results in sliding from the current page to the target page, which causes the intermediate pages between the current and target pages to be loaded as well.

  • LazyForEach must be used within container components. Only List, ListItemGroup, Grid, Swiper, and WaterFlow components support lazy data loading. Other components still load all data at once. Refer to Usage Restrictions.
  • Custom Tabs page transition animation, refer to customContentTransition.

Solution

Solution 1:

Since the Tabs component has a built-in sliding animation for page switching, clicking the tabBar to switch pages causes a slide from the current page to the target page, resulting in the loading of intermediate pages. This can be avoided by using a custom transition animation. Refer to the customContentTransition usage instructions.

Sample code as follows:

@Entry
@Component
struct TabsDemo {
  @State currentIndex: number = 0
  private tabsController: TabsController = new TabsController()
  // Set page transition animations to replace the swipe-to-navigate page transition animations.
  private customContentTransition: (from: number, to: number) => TabContentAnimatedTransition =
    (from: number, to: number) => {
      let tabContentAnimatedTransition = {
        timeout: 1000,
        transition: (proxy: TabContentTransitionProxy) => {
          this.getUIContext().animateTo({
            duration: 0,
            onFinish: () => {
              proxy.finishTransition()
            }
          }, () => {
          })
        }
      } as TabContentAnimatedTransition
      return tabContentAnimatedTransition
    }

  build() {
    Column() {
      Tabs({ index: this.currentIndex, controller: this.tabsController }) {
        TabContent() {
          MyComponent({ color: '#00CB87' })
        }.tabBar(SubTabBarStyle.of('green'))

        TabContent() {
          MyComponent({ color: '#007DFF' })
        }.tabBar(SubTabBarStyle.of('blue'))

        TabContent() {
          MyComponent({ color: '#FFBF00' })
        }.tabBar(SubTabBarStyle.of('yellow'))

        TabContent() {
          MyComponent({ color: '#E67C92' })
        }.tabBar(SubTabBarStyle.of('pink'))
      }
      .customContentTransition(this.customContentTransition)
      .width('100%')
      .height('100%')

      .onChange((index: number) => {
        this.currentIndex = index
      })
    }

    .backgroundColor(Color.White)
    .padding(10)
  }
}

@Component
struct MyComponent {
  @Prop color: string = ""

  aboutToAppear(): void {
    console.info('------aboutToAppear backgroundColor:' + this.color) // By reviewing the log output,
    // it can be observed that the intermediate page was not loaded.
  }

  aboutToDisappear(): void {
    console.info('------aboutToDisappear backgroundColor:' + this.color)
  }

  build() {
    Column() {
      Text(this.color)
        .fontColor(Color.White)
        .textAlign(TextAlign.Center)
        .fontSize(30)
    }
    .borderRadius(10)
    .width('90%')
    .height('90%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor(this.color)
  }
}
Enter fullscreen mode Exit fullscreen mode

Runtime log as follows, which avoids loading the intermediate tabs:

08-13 10:25:53.034   22832-22832   A03d00/JSAPP                    com.example.ir_test   I     ------aboutToAppear backgroundColor:#00CB87
08-13 10:26:04.021   22832-22832   A03d00/JSAPP                    com.example.ir_test   I     ------aboutToAppear backgroundColor:#E67C92
08-13 10:26:05.250   22832-22832   A03d00/JSAPP                    com.example.ir_test   I     ------aboutToAppear backgroundColor:#FFBF00
Enter fullscreen mode Exit fullscreen mode

Solution 2:
To both avoid loading intermediate pages and retain the gesture-based swipe functionality for page switching, you can use a Swiper to custom-implement the Tabs component. By calling the changeIndex method of SwiperController, you can switch to a specific page. When useAnimation is set to false, there is no animation effect.

Sample code as follows:

class MyDataSource implements IDataSource {
  private list: number[] = []

  constructor(list: number[]) {
    this.list = list
  }

  totalCount(): number {
    return this.list.length
  }

  getData(index: number): number {
    return this.list[index]
  }

  registerDataChangeListener(listener: DataChangeListener): void {
  }

  unregisterDataChangeListener() {
  }
}

@Entry
@Component
struct SwiperExample {
  private swiperController: SwiperController = new SwiperController()
  private data: MyDataSource = new MyDataSource([])

  aboutToAppear(): void {
    let list: number[] = []
    for (let i = 1; i <= 10; i++) {
      list.push(i);
    }
    this.data = new MyDataSource(list)
  }

  build() {
    Column({ space: 5 }) {
      Swiper(this.swiperController) {
        LazyForEach(this.data, (item: string) => {
          Text(item.toString())
            .width('90%')
            .height('50%')
            .borderRadius(10)
            .fontColor(Color.Black)
            .backgroundColor($r('sys.color.comp_background_focus'))
            .textAlign(TextAlign.Center)
            .fontSize(30)
        }, (item: string) => item)
      }
      .cachedCount(2)
      .index(1)
      .autoPlay(true)
      .interval(4000)
      .loop(true)
      .duration(1000)
      .itemSpace(0)
      .indicator(false)
      Column({ space: 12 }) {
        Button('change to index:4')
          .onClick(() => {
            this.swiperController.changeIndex(3,false)
          })
        Button('change to index:7')
          .onClick(() => {
            this.swiperController.changeIndex(6,false)
          })
      }.margin(5)
    }
    .height('100%')
    .width('100%')
    .margin({ top: 5 })
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • The default sliding animation in Tabs can cause unwanted loading of intermediate pages.
  • Using customContentTransition can override the default animation and prevent intermediate page loading.
  • Implementing Tabs using Swiper provides more control, including disabling animation while preserving swipe gestures.

Reference Links

Written by Mehmet Karaaslan

Top comments (0)