HarmonyOS鸿蒙Next中Swiper实践分享:Swiper组件如何做同屏多个,每个宽度不一样的效果

HarmonyOS鸿蒙Next中Swiper实践分享:Swiper组件如何做同屏多个,每个宽度不一样的效果

如果想要实现同屏多个子页面,并且每个子页面宽度不一样的效果,可以考虑使用Swiper的自定义动画。在自定义动画中,可以自由控制每个子页面的scale和translate属性。

3 回复

可以参考以下demo:

// xxx.ets

@Entry
@Component
struct SwiperCustomAnimationExample {
  private DISPLAY_COUNT: number = 2;
  private MIN_SCALE: number = 0.75;

  @State backgroundColors: Color[] = [Color.Green, Color.Blue, Color.Yellow, Color.Pink, Color.Gray, Color.Orange];
  @State opacityList: number[] = [];
  @State scaleList: number[] = [];
  @State translateList: number[] = [];
  @State zIndexList: number[] = [];

  aboutToAppear(): void {
    for (let i = 0; i < this.backgroundColors.length; i++) {
      this.opacityList.push(1.0);
      this.scaleList.push(1.0);
      this.translateList.push(0.0);
      this.zIndexList.push(0);
    }
  }

  build() {
    Column() {
      Swiper() {
        ForEach(this.backgroundColors, (backgroundColor: Color, index: number) => {
          Text(index.toString()).width('100%').height('100%').fontSize(50).textAlign(TextAlign.Center)
            .backgroundColor(backgroundColor)
            // 自定义动画变化透明度、缩放页面、抵消系统默认位移、渲染层级等
            .opacity(this.opacityList[index])
            .scale({ x: this.scaleList[index], y: this.scaleList[index] })
            .translate({ x: this.translateList[index] })
            .zIndex(this.zIndexList[index])
        })
      }
      .height(300)
      .indicator(false)
      .displayCount(this.DISPLAY_COUNT, true)
      .customContentTransition({
        // 页面移除视窗时超时1000ms下渲染树
        timeout: 1000,
        // 对视窗内所有页面逐帧回调transition,在回调中修改opacity、scale、translate、zIndex等属性值,实现自定义动画
        transition: (proxy: SwiperContentTransitionProxy) => {
          
            if (proxy.position <= proxy.index % this.DISPLAY_COUNT || proxy.position >= this.DISPLAY_COUNT + proxy.index % this.DISPLAY_COUNT) {
              // 同组页面往左滑或往右完全滑出视窗外时,重置属性值
              this.opacityList[proxy.index] = 1.0;
              this.scaleList[proxy.index] = 1.0;
              this.translateList[proxy.index] = 0.0;
              this.zIndexList[proxy.index] = 0;
            } else {
              // 同组页面往右滑且未滑出视窗外时,对同组中左右两个页面,逐帧根据position修改属性值,实现两个页面往Swiper中间靠拢并透明缩放的自定义切换动画
              if (proxy.index % this.DISPLAY_COUNT === 0) {
                this.opacityList[proxy.index] = 1 - proxy.position / this.DISPLAY_COUNT;
                this.scaleList[proxy.index] = this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - proxy.position / this.DISPLAY_COUNT);
                this.translateList[proxy.index] = -proxy.position * proxy.mainAxisLength + (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0;
              } else {
                this.opacityList[proxy.index] = 1 - (proxy.position - 1) / this.DISPLAY_COUNT;
                this.scaleList[proxy.index] = this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - (proxy.position - 1) / this.DISPLAY_COUNT);
                this.translateList[proxy.index] = -(proxy.position - 1) * proxy.mainAxisLength - (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0;
              }
              this.zIndexList[proxy.index] = -1;
            }
          
        }
      })
      .onContentDidScroll((selectedIndex: number, index: number, position: number, mainAxisLength: number) => {
        // 监听Swiper页面滑动事件,在该回调中可以实现自定义导航点切换动画等
        console.info("onContentDidScroll selectedIndex: " + selectedIndex + ", index: " + index + ", position: " + position + ", mainAxisLength: " + mainAxisLength);
      })
    }.width('100%')
  }
}

更多关于HarmonyOS鸿蒙Next中Swiper实践分享:Swiper组件如何做同屏多个,每个宽度不一样的效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中实现同屏多个宽度不同的Swiper组件,可使用Swiper的displayMode属性设置为autoLinear模式,并自定义每个Swiper子项的宽度。通过设置itemSize为固定值或百分比来控制宽度差异。在布局文件中为每个Swiper子项单独设置宽度样式,或使用ForEach动态绑定不同宽度值。示例代码片段:

Swiper({
  displayMode: SwiperDisplayMode.AutoLinear,
  itemSize: '50%' // 可根据需求设置为不同值
}) {
  ForEach(this.items, (item, index) => {
    Column() {
      // 内容
    }.width(this.getItemWidth(index)) // 动态宽度函数
  })
}

在HarmonyOS Next中实现同屏多个不同宽度Swiper组件的效果,可以通过以下方案实现:

  1. 核心思路是利用Swiper的loop和customStyle属性配合自定义动画:
Swiper({
  loop: true,
  customStyle: true
}) {
  // 子页面内容
}
  1. 为每个子项设置不同宽度:
ForEach(this.items, (item, index) => {
  Column() {
    // 内容
  }
  .width(`${item.width}%`) // 设置不同宽度
  .height('100%')
}, (item) => item.id)
  1. 关键点:
  • 使用customStyle:true启用自定义样式
  • 通过transform控制位置和缩放
  • 配合onChange事件动态调整样式
  • 建议设置itemSpace留出间距
  1. 完整示例:
@State currentIndex: number = 0

build() {
  Swiper({
    loop: true,
    customStyle: true,
    onChange: (index: number) => {
      this.currentIndex = index
    }
  }) {
    ForEach(this.items, (item, index) => {
      Column() {
        // 内容
      }
      .width(`${item.width}%`)
      .transform(this.getTransform(index))
    })
  }
}

private getTransform(index: number): object {
  // 根据currentIndex计算每个item的transform值
  // 可以实现错位、缩放等效果
}

注意要合理处理item间距和transform计算,确保滑动流畅性和视觉效果。

回到顶部